数据库切换报错'Grid index out of range'
The error 'Grid index out of range' when switching between the databases
这是显示客户数据库的程序:
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;
当我 运行 程序时,我可以在第一次单击时打开其中一个数据库,但是如果我再次单击“客户”或“员工”按钮中的任何一个或尝试更改数据库,则会出现以下情况错误显示:"Project ProjectQuote.exe raised exception class EInvalidGridOperation with message 'Grid index out of range'"。
如果我删除行
sgdDatabases.RowCount := sgdDatabases.RowCount + 1;
从代码来看,它显示了两个数据库,但只显示了数据库的前四行,即使还有更多行也是如此。
(我知道无用的重复代码,不,我不能使用除 TStringGrid 以外的任何东西)
你的这行代码在我看来是错误的:
for j := 0 to sgdDatabases.rowCount do
sgdDatabases.ColWidths[j] := 100;
StringGrid的ColWidths
属性的[Index]是列号,不是行号,所以sgdDatabases.rowCount
应该与它无关。如果在执行上述代码时,网格中的行数大于列数,当 j 的值达到表示无效列号的值时,您将收到 "Index out of range" 错误。
无论如何,即使该代码在这方面是有效的,也存在涉及 sgdDatabases.rowCount
的 "off by one" 错误。行号是从零开始的,因此它应该是 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;
这样做的好处之一是您的所有错误都集中在一个地方,而不是在重复的代码中重复出现,所以如果您修复一次错误,您就大功告成了。
这是显示客户数据库的程序:
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;
当我 运行 程序时,我可以在第一次单击时打开其中一个数据库,但是如果我再次单击“客户”或“员工”按钮中的任何一个或尝试更改数据库,则会出现以下情况错误显示:"Project ProjectQuote.exe raised exception class EInvalidGridOperation with message 'Grid index out of range'"。
如果我删除行
sgdDatabases.RowCount := sgdDatabases.RowCount + 1;
从代码来看,它显示了两个数据库,但只显示了数据库的前四行,即使还有更多行也是如此。
(我知道无用的重复代码,不,我不能使用除 TStringGrid 以外的任何东西)
你的这行代码在我看来是错误的:
for j := 0 to sgdDatabases.rowCount do
sgdDatabases.ColWidths[j] := 100;
StringGrid的ColWidths
属性的[Index]是列号,不是行号,所以sgdDatabases.rowCount
应该与它无关。如果在执行上述代码时,网格中的行数大于列数,当 j 的值达到表示无效列号的值时,您将收到 "Index out of range" 错误。
无论如何,即使该代码在这方面是有效的,也存在涉及 sgdDatabases.rowCount
的 "off by one" 错误。行号是从零开始的,因此它应该是 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;
这样做的好处之一是您的所有错误都集中在一个地方,而不是在重复的代码中重复出现,所以如果您修复一次错误,您就大功告成了。