【发布时间】:2015-11-08 00:54:36
【问题描述】:
我正在使用 Delphi XE8 编写一个可以访问多个数据库的客户端/服务器应用程序。
作为设置表单的一部分,TComboBoxEx 用于显示和选择动态记录数组,其中包含每个数据库的信息,两个按钮用于在数组中添加或删除记录。
数组保存和加载到单个格式化字符串,每条记录的名称属性用作每个组合框项的标题。
在表单显示和添加或删除数据库按钮按下更新过程时调用,该过程首先清除并重新加载数组,然后重新填充组合框。
procedure TSettingsForm.UpdateDatabaseCombo;
var
i: integer;
begin
LoadDatabaseList; // Clears and reloads databaselist dynamic array.
with dbCombo.Items do
begin
BeginUpdate;
if Length(DatabaseList) <> 0 then
begin
Clear; // This section works fine.
for i := 0 to High(DatabaseList) do
begin
Add(DatabaseList[i].dbName);
dbCombo.ItemsEx[i].ImageIndex := 17;
end;
end;
if (Length(DatabaseList) < 1) and (Count <> 0) then
begin
Clear; // Access violation on this line.
end;
EndUpdate;
end;
end;
该过程在启动时初始加载数组时运行良好,即使没有保存记录,并且添加了新记录。 但是,在删除记录期间会出现问题,或者我应该说在删除记录后更新组合框(从数据库列表中删除记录没有问题)。
如果数组中存储的记录不止一个,一切正常,组合框将被清除并重新填充。然而,如果要删除的记录是最后存储的,即索引 0,如前所述,记录会按预期从数组中删除,但组合框更新过程在调用 clear 方法时会抛出错误Access violation at address 0040B2D2 in module ***** Read of address FFFFFFE7。之后组合框项目列表被清除,但最后一个选定项目的文本仍然存在。
我尝试了许多不同的方法来解决这个问题,接近成功的方法是使用删除项目方法,
Delete(dbCombo.ItemIndex);
这将再次从组合框中清除最后一项,无一例外,但文本仍然保留。
请任何人帮助解决这个问题,并指出我缺少的简单的小东西。
Addition........
根据要求,这是UpdateDatabaseCombo 例程的更新代码,
procedure TSettingsForm.UpdateDatabaseCombo;
var
i: integer;
begin
LoadDatabaseList; // Clears and reloads databaselist dynamic array.
if dbCombo.Items.Count <> 0 then
dbCombo.Items.Clear;
with dbCombo.Items do
begin
BeginUpdate;
if Length(DatabaseList) <> 0 then
begin
for i := 0 to High(DatabaseList) do
begin
Add(DatabaseList[i].dbName);
dbCombo.ItemsEx[i].ImageIndex := 17;
end;
end;
EndUpdate;
end;
end;
我注意到,如果在没有检查 items.count 值是否大于 0 的情况下调用 items.clear 并且每次调用例程时都会引发异常,并且计数检查到位,只会引发异常当组合框中的最后一项被删除时。
我还添加了从数组中删除记录的例程,
procedure TSettingsForm.DBRemoveButtonClick(Sender: TObject);
var
ALength: Cardinal;
i: Cardinal;
begin
ALength := Length(DatabaseList);
Assert(ALength > 0);
Assert(dbCombo.ItemIndex < ALength);
for i := dbCombo.ItemIndex + 1 to ALength - 1 do
DatabaseList[i - 1] := DatabaseList[i];
SetLength(DatabaseList, ALength - 1);
SaveDatabaseList;
UpdateDatabaseCombo;
if dbCombo.Items.Count <> 0 then
dbCombo.ItemIndex := 0;
end;
如果在组合框为空时调用clear,程序中的任何地方也会发生异常。
【问题讨论】:
-
去掉
with语句,改为对每个属性使用dbCombo.Items,然后使用调试器找出问题所在。这是在代码中使用with时可能发生的坏事的又一个例子。它使问题难以发现并且无法调试(至少在您做正确的事情并消除使用with之前)。 -
感谢@Ken 的回复,但在这种情况下你错了,因为问题不在于
with循环,为了证明这一点,我删除了第二个if语句替换为if dbCombo.Items.Count <> 0 then dbCombo.Items.Clear加载数组后立即但结果仍然是相同的异常错误。 ps 对上一条评论感到抱歉,误按了回车。 -
@KenWhite 没有错:无论如何,您都应该避免使用“with”。无论如何,我怀疑你的问题在于你没有向我们展示的东西。调用 dbCombo.Items.Clear 两次不应导致 AV。请在您的 q 中添加您在 DatabaseList 中添加和删除记录的代码。
-
@Ken,请原谅我,我并不是说您对
with的使用有误,我只是说在这种情况下这不是问题的原因,反正我现已更新问题以提供更多信息。 -
我认为您应该尝试在您的配置中启用“使用调试 dcu”。然后运行。然后使用调用堆栈找出调用组合框清除时异常究竟发生在哪里。
标签: arrays delphi combobox delphi-xe8