在数据库之间切换时,错误“网格索引超出范围”

时间:2015-12-10 14:42:20

标签: sql database sqlite delphi delphi-xe8

这是显示客户数据库的过程:

    procedure TfrmMain.mnuCustomerClick(Sender: TObject);
    var
      j: integer;
    begin

      con := TFDConnection.Create(nil);
      query := TFDQuery.Create(con);
      con.LoginPrompt := False;
      con.Open('DriverID=SQLite;Database=C:\Users\katiee\Documents\Embarcadero\Studio\Projects\ProgramDatabase;');
      query.Connection := con;
      query.sql.Text := 'SELECT * FROM CustDatabase ORDER BY ID';
      query.Open();
      query.First;

      sgdDatabases.colCount := 9;
      sgdDatabases.FixedCols := 0;
      for j := 0 to sgdDatabases.rowCount do
      sgdDatabases.ColWidths[j] := 100;

      sgdDatabases.Cells[0, 0] := 'ID';
      sgdDatabases.Cells[1, 0] := 'First Name';
      sgdDatabases.Cells[2, 0] := 'Last Name';
      sgdDatabases.Cells[3, 0] := 'Address';
      sgdDatabases.Cells[4, 0] := 'Town';
      sgdDatabases.Cells[5, 0] := 'County';
      sgdDatabases.Cells[6, 0] := 'Postcode';
      sgdDatabases.Cells[7, 0] := 'Telephone No.';
      sgdDatabases.Cells[8, 0] := 'E-Mail';

      row := 1;
      while not query.EOF do
      begin
        ID := query.FieldByName('ID').AsString;
        firstname := query.FieldByName('First Name').AsString;
        lastname := query.FieldByName('Last Name').AsString;
        address := query.FieldByName('Address').AsString;
        town := query.FieldByName('Town').AsString;
        county := query.FieldByName('County').AsString;
        postcode := query.FieldByName('Postcode').AsString;
        telno := query.FieldByName('TelNo').AsString;
        email := query.FieldByName('Email').AsString;

        sgdDatabases.Cells[0, row] := ID;
        sgdDatabases.Cells[1, row] := firstname;
        sgdDatabases.Cells[2, row] := lastname;
        sgdDatabases.Cells[3, row] := address;
        sgdDatabases.Cells[4, row] := town;
        sgdDatabases.Cells[5, row] := county;
        sgdDatabases.Cells[6, row] := postcode;
        sgdDatabases.Cells[7, row] := telno;
        sgdDatabases.Cells[8, row] := email;

        sgdDatabases.RowCount := sgdDatabases.RowCount + 1;
        row := row + 1;
        query.Next;

         end;
       end;

这是显示员工数据库的过程,除了“SELECT * FROM EmplDatabase”之外基本相同:

    procedure TfrmMain.mnuEmployeeClick(Sender: TObject);
    var
      i: integer;
    begin

      con := TFDConnection.Create(nil);
      query := TFDQuery.Create(con);
      con.LoginPrompt := False;
      con.Open('DriverID=SQLite;Database=C:\Users\kasio\Documents\Embarcadero\Studio\Projects\ProgramDatabase;');
      query.Connection := con;
      query.sql.Text := 'SELECT * FROM EmplDatabase ORDER BY ID';
      query.Open();
      query.First;

      sgdDatabases.colCount := 9;
      sgdDatabases.FixedCols := 0;
      for i := 0 to sgdDatabases.RowCount do
      sgdDatabases.ColWidths[i] := 100;

      sgdDatabases.Cells[0, 0] := 'ID';
      sgdDatabases.Cells[1, 0] := 'First Name';
      sgdDatabases.Cells[2, 0] := 'Last Name';
      sgdDatabases.Cells[3, 0] := 'Address';
      sgdDatabases.Cells[4, 0] := 'Town';
      sgdDatabases.Cells[5, 0] := 'County';
      sgdDatabases.Cells[6, 0] := 'Postcode';
      sgdDatabases.Cells[7, 0] := 'Telephone No.';
      sgdDatabases.Cells[8, 0] := 'E-Mail';

      row := 1;
      while not query.EOF do
      begin
        ID := query.FieldByName('ID').AsString;
        firstname := query.FieldByName('First Name').AsString;
        lastname := query.FieldByName('Last Name').AsString;
        address := query.FieldByName('Address').AsString;
        town := query.FieldByName('Town').AsString;
        county := query.FieldByName('County').AsString;
        postcode := query.FieldByName('Postcode').AsString;
        telno := query.FieldByName('TelNo').AsString;
        email := query.FieldByName('Email').AsString;

        sgdDatabases.Cells[0, row] := ID;
        sgdDatabases.Cells[1, row] := firstname;
        sgdDatabases.Cells[2, row] := lastname;
        sgdDatabases.Cells[3, row] := address;
        sgdDatabases.Cells[4, row] := town;
        sgdDatabases.Cells[5, row] := county;
        sgdDatabases.Cells[6, row] := postcode;
        sgdDatabases.Cells[7, row] := telno;
        sgdDatabases.Cells[8, row] := email;

        sgdDatabases.RowCount := sgdDatabases.RowCount + 1;
        row := row + 1;
        query.Next;

        end;
      end;

当我运行程序时,我可以在第一次单击时打开任一数据库,但如果我再次单击Customer或Employee按钮或尝试更改数据库,则会出现以下错误:“Project ProjectQuote .exe引发异常类EInvalidGridOperation,消息'Grid index out of range'“。

如果删除该行

  

sgdDatabases.RowCount:= sgdDatabases.RowCount + 1;

从代码

,它显示两个数据库,但只显示数据库中的前四行,即使还有更多。

(我知道无用的重复代码,除了TStringGrid,我不能使用其他任何东西)

1 个答案:

答案 0 :(得分:5)

你的代码这行代码对我来说不对:

for j := 0 to sgdDatabases.rowCount do
  sgdDatabases.ColWidths[j] := 100;

StringGrid的ColWidths属性的[Index]是列号,而不是行号,因此sgdDatabases.rowCount应该与它无关。如果在上面的代码执行时,网格中的行数大于列数,则会得到一个"索引超出范围"当j的值达到表示无效列号的值时出错。

在任何情况下,即使该代码在这方面有效,也会有一个"关闭一个"涉及sgdDatabases.rowCount的错误。行号从零开始,因此它应该是sgdDatabases.rowCount - 1(假设您尝试通过索引引用特定的)。

更一般的一点是,您可以使用IDE的调试器单步执行代码;如果你这样做,你会看到在执行一个特定行时发生异常,并且这是开始寻找原因的地方。您应该始终在SO问题中包含异常的位置,因为读者不应该猜到这一点。

通常,只要你去

,即使你不是单步,IDE调试器也会发现异常。

Tools | Debugger Options | Embarcadero Debuggers | Language Exceptions

在IDE中

并选中复选框Notify on Language Exceptions

顺便说一句,如果你编写一个通用例程来从数据集中填充StringGrid会更好,可能会沿着以下几行:

procedure TForm1.DatasetToGrid(Dataset : TDataset; Grid : TStringGrid);
var
  Col,
  Row : Integer;
begin

  Grid.RowCount := 1;
  Row := 0;

  // The following gives the column headers the names of the
  // Dataset fields.  
  for Col := 0 to Dataset.FieldCount - 1 do
    Grid.Cells[Col, Row] := Dataset.Fields[Col].FieldName;

  Inc(Row);
  Dataset.First;
  while not Dataset.Eof do begin
    for Col := 0 to Dataset.FieldCount - 1 do begin
      //  Oops! we don't need this Row := Grid.RowCount;
      Grid.Cells[Col, Row] := DataSet.Fields[Col].AsString;;
    end;
    Dataset.Next;
    Grid.RowCount := Grid.RowCount + 1;
    Inc(Row);
  end;
end;

这样做的好处之一就是你的所有错误都在一个地方,而不是重复的代码中重复,所以如果你修复它们,你就完成了。