1

我有一个列表records,我想总结成一个TListView

记录结构如下

MyRecord = record
   SourceTable: string;
   SourceField: string;
   TargetTable: string;
   TargetField: string;
end;

记录中可能有 SourceTable / TargetTable 的多个实例,Source/Target Field 的单个实例

我想创建一个TListViewin vsReport 样式来总结每个 SourceTable\TargetTable 对。

理想情况下,我想做以下事情:

procedure SetTables;
var
   mp: MyPointer;
   LI: TListItem;
begin
   LI := LI.Create(nil);
   LI.Caption := ap^.SourceTable;
   LI.SubItems.Add(ap^.TargetTable);
   LI.Checked := not ap^.Updated;
   if lvMigration.Items.IndexOf(LI) = -1 then
       lvMigration.Items.AddItem(LI);
end;

即创建一个独立的TListItem,检查它不存在,然后将它添加到我的TListView。然而,它在分配时中断LI.Caption- 基本上没有什么可分配的。我怀疑至少部分问题是(nil)

TListItem 的正常创建将是使用LI := lvMigration.Items.Add;,但这对我的用例没有帮助。我似乎找不到任何完成上述操作的文档。

4

2 回答 2

1

代替:

LI := LI.Create(nil);

你的意思是写

LI := TListItem.Create(nil);

这是书中最古老的 Delphi 错误,我敢肯定你以前犯过(我们都犯过),而且当你看到它时,我敢肯定你会认出它。

但是,您的其余代码将不起作用。如果TListItem不提供Owner. 例如,看一下以下的实现TListItem.SetCaption

procedure TListItem.SetCaption(const Value: string);
begin
  if Value <> Caption then
  begin
    FCaption := Value;
    if not Owner.Owner.OwnerData then
    .... 
  end;
end;

使用您的代码,Ownernil,因此此代码只会导致访问冲突。事实上,你TListItem永远不应该实例化。这是由容器类完成的。

但是,即使没有这个问题,您也会发现这IndexOf并不能满足您的要求。您希望它对项目的执行搜索。但它会在reference上执行搜索。

您需要做的是遍历列表中的每个项目,并根据预期的新值检查其标题和子项目(或标识该项目的任何内容)。

如果您想进行更剧烈的更改,从长远来看可以使生活更轻松,并在列表变大时提高性能,那么切换到在虚拟模式下使用列表视图会有所帮助。你会维护一个TList<TMyItem>或类似的项目列表。然后你会按需填充。如果您这样做了,那么检测重复项会容易得多,因为您将使用普通容器而不是 GUI 控件。从根本上说,通过将 GUI 控件用作容器类,您正在为自己感到难过。

于 2013-10-30T15:57:18.920 回答
0

我建议您将主记录列表排序到第二个列表中,过滤掉重复项,然后使用第二个列表填充 ListView。我还建议在虚拟模式下使用 ListView(将其 OwnerData 属性设置为 true,然后使用其 OnData... 事件)。这将大大提高 ListView 的性能,然后您可以访问/操作内存中的记录,而不会被 UI 拖慢。

于 2013-10-30T16:10:08.910 回答