在delphi7

时间:2016-08-30 06:27:19

标签: delphi delphi-7

我需要做的是从 excel 文件中读取表格详细信息,并希望从中创建 .pas 文件。

出于读写目的,我在 delphi 7 中使用了记录类型。

以下是我迄今为止尝试过的代码:

unit fImportFile;
interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    tSourceFile: TEdit;
    dlgSourceFile: TOpenDialog;
    btnImport: TButton;
    procedure tSourceFileClick(Sender: TObject);
    procedure btnImportClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TTableDetails = record
    fTableName: String;
  end;

  TFieldDetails = record
    fFieldName: String;
    fType: String;
    fShortAlias: String;
    fLongAlias: String;
    fDomainName: String;
    fFieldAttributes:TStringList;
    fComments: String;
  end;

var
  Form1: TForm1;

implementation

uses ComObj, uFileGeneration;

{$R *.dfm}

procedure TForm1.tSourceFileClick(Sender: TObject);
begin
  with dlgSourceFile do
  begin
    FileName := tSourceFile.Text;
    if ExtractFilePath(FileName) <> '' then
      InitialDir := ExtractFilePath(FileName);
    if Execute then
      if FileName <> '' then
        tSourceFile.Text := FileName;
  end;

end;

procedure TForm1.btnImportClick(Sender: TObject);
const
  cEndOfTables = '';
  cTable = 'Table';
  cTableCell = 2;
  cTableNameCell = 3; // TableNameField
  cFieldName = 'Field Name';
var
  Excel: OleVariant;
  iRow: Integer;
  aTableDetails: TTableDetails;
  aFieldDetails: Array of TFieldDetails;
  fieldCount: Integer;
  iTableName, FldWithChar, FldWithoutChar: String;
  FldList, WordList: TStringList;
  FieldName: String;
begin
  FldList := nil;
  WordList := nil;

  try
    Excel := CreateOleObject('Excel.Application');
    Excel.Visible := False;
    Excel.Workbooks.Open(tSourceFile.Text);
    iRow := 1;

    while (Excel.ActiveSheet.Cells[iRow,cTableCell].Value <> '') do //To exit loop when the excel record will read blank TableName
    begin
      if (Excel.ActiveSheet.Cells[iRow,cTableCell].Value = cTable) then
      begin
        iTableName := Excel.ActiveSheet.Cells[iRow,cTableNameCell].Value;
        if (iTableName = '') then
        begin
          ShowMessage('Table Name cannot be blank.');
          exit;
        end;
        aTableDetails.fTableName := iTableName;
        Inc(iRow);

        fieldCount := 0;
        FldList := TStringList.Create;
        WordList := TStringList.Create;
        ShowMessage('1 -- iRow --> ' + IntToStr(iRow));

        while (Excel.ActiveSheet.Cells[iRow,cTableCell].Value <> '') AND
          (Excel.ActiveSheet.Cells[iRow,cTableCell].Value <> cTable) do //Will create record until another table will found
        begin
          ShowMessage('2 -- Excel.ActiveSheet.Cells[iRow,cTableNameCell].Value = ' + Excel.ActiveSheet.Cells[iRow,cTableNameCell].Value);
          FieldName := Excel.ActiveSheet.Cells[iRow,cTableNameCell].Value;
          aFieldDetails[fieldCount].fFieldName := FieldName; //ERROR LINE

          ShowMessage('3 -- iRow --> ' + IntToStr(iRow));
          FldWithChar := aFieldDetails[fieldCount].fFieldName;
          FldWithoutChar := NameWithoutAnyChar(FldWithChar, WordList);
          FldList.Add(FldWithChar + '=' + FldWithoutChar);
          WordList.Clear;
          ShowMessage('4 -- iRow --> ' + IntToStr(iRow));

          if (aFieldDetails[fieldCount].fFieldName = '') then
          begin
            ShowMessage('Field Name cannot be blank. TableName: '+iTableName);
            exit;
          end;
          aFieldDetails[fieldCount].fType := Excel.ActiveSheet.Cells[iRow,3].Value;
          aFieldDetails[fieldCount].fShortAlias := Excel.ActiveSheet.Cells[iRow,4].Value;
          aFieldDetails[fieldCount].fLongAlias := Excel.ActiveSheet.Cells[iRow,5].Value;
          aFieldDetails[fieldCount].fDomainName := Excel.ActiveSheet.Cells[iRow,6].Value;
          aFieldDetails[fieldCount].fFieldAttributes.CommaText := Excel.ActiveSheet.Cells[iRow,7].Value;
          aFieldDetails[fieldCount].fComments := Excel.ActiveSheet.Cells[iRow,8].Value;
          Inc(fieldCount);
          Inc(iRow);
        end;
        //Once new table row will be fouund it will call below method to create a dataview file for current table
        ShowMessage('5 -- iRow --> ' + IntToStr(iRow));
        GenerateDataviewFiles(aTableDetails, aFieldDetails, FldList, fieldCount-1);
        ShowMessage('6 -- iRow --> ' + IntToStr(iRow));
      end; //End of If condition
    end; //End of outer most while loop
  finally
    FreeAndNil(WordList);
    FreeAndNil(FldList);
    Excel.Workbooks.Close;
    Excel.Quit;
    Excel := Unassigned;
  end;
end;
end.

我评论了 //错误行,我收到了访问冲突错误。

我在这里做的是,创建 TFieldDetails数组并希望在另一个文件中循环它。

请帮我解决这个问题,因为我是delphi的新手。

2 个答案:

答案 0 :(得分:4)

问题在于您尝试访问超出范围的aFieldDetails索引。您应该在此之前设置动态数组的长度。像这样:

...
SetLength(aFieldDetails, fieldCount+1);
aFieldDetails[fieldCount].fFieldName := FieldName; //ERROR LINE
...

但是,除非您知道自开始以来总共有多少字段,否则性能会很差。这是因为每次调用SetLength时,都会分配另一块内存,并将整个数组复制到其中。

我建议您使用TList,即使您不知道要将多少项添加到列表中,也会尝试保持良好的效果。

答案 1 :(得分:3)

您忘记初始化动态数组aFieldDetails。因此,当您尝试使用索引fieldCount写入时,其长度仍为零。

如果您知道字段总数,则应通过调用

来预先分配完整数组
SetLength(aFieldDetails, TheTotalFieldCount);

如果您事先不知道总计数,则可以使用列表或其他动态数据结构,因为每次添加项目时重新分配在性能方面都非常昂贵。

aFieldDetailList := TList.Create;
try
  while (Excel.ActiveSheet.Cells[iRow,cTableCell].Value <> '') AND
        (Excel.ActiveSheet.Cells[iRow,cTableCell].Value <> cTable) do //Will create record until another table will found
  begin
    New(aFieldDetail); // create a new instance of aFieldDetail; aFieldDetail is of pointer type "^TFieldDetails"

    // do your loop work
  end;
  // do your after-loop work
finally
  // free all allocated memory
  for aFieldDetail in aFieldDetailList do
    Dispose(aFieldDetail);
  FreeAndNil(aFieldDetailList);
end;