使用临时 TListItems 填充 TListView
populating TListView by using temp TListItems
我想在后台刷新列表视图列表,为此我创建了一个临时 TListItems,但我无法将它分配给我的列表视图。如果我创建 TListItems 和 TListItem,则会发生访问冲突错误;
var
lis:TListItems;
li:TListItem;
begin
lis := TListItems.Create(nil);
try
li := TListItem.Create(nil);
li.Caption := 'test'; // at this line av occurs
lis.AddItem(li);
ListView1.Items.BeginUpdate;
try
ListView1.Items.Assign(lis);
finally
ListView1.Items.EndUpdate;
end;
finally
lis.Destroy();
end;
如果我在创建 TListItems 时使用 ListView1 作为所有者,则不会出现新行;
var
lis:TListItems;
li:TListItem;
begin
lis := TListItems.Create(ListView1);
try
li := TListItem.Create(lis);
li.Caption := 'test';
lis.AddItem(li);
ListView1.Items.BeginUpdate;
try
ListView1.Items.Assign(lis);
finally
ListView1.Items.EndUpdate;
end;
finally
lis.Destroy();
end;
所以我想在后台准备一个新列表并将其分配给列表视图,我该怎么做?
注意:准备列表需要很长时间,这就是我在后台准备的原因。 (我正在用线程填充列表并使用 TRTLCriticalSection 保护它)
TListItems
和 TListItem
与 TListView
密切相关,因此不能像您尝试的那样以独立方式使用。 TListItems
和 TListItem
都委托给 TListView
来处理他们的工作。
您在第一个示例中获得了 AV,因为没有分配 TListView
来处理该工作。
在你的第二个例子中,新的列表项没有正确显示,因为当你分配它的 Caption
时它还没有被添加到 ListView,所以 属性 setter更新。 AddItem()
不会将预先存在的 属性 值应用到新插入的列表项。必须使用单独的 属性 setter。
你必须首先使用TListItems.Add()
方法而不是直接调用AddItem()
,然后你可以根据需要修改新的TListItem
,例如:
var
NewList: TStringList;
Lock: TCriticalSection;
...
// in a worker thread...
Lock.Enter;
try
NewList.Clear;
NewList.Add('test');
...
finally
Lock.Leave;
end;
// signal main UI thread that a new list is ready ...
...
// in the main UI thread when the signal is received...
var
li: TListItem;
i: Integer;
begin
Lock.Enter;
try
ListView1.Items.BeginUpdate;
try
ListView1.Items.Clear;
for i := 0 to NewList.Count-1 do
begin
li := ListView1.Items.Add;
li.Caption := NewList[i];
...
end;
finally
ListView1.Items.EndUpdate;
end;
finally
Lock.Leave;
end;
end;
但是,正如 David H 在评论中所说,在虚拟模式下使用 ListView(将 OwnerData
属性 设置为 true
并使用 TListView.OnData...
事件)是处理这种情况的更好方法:
var
NewList: TStringList;
Lock: TCriticalSection;
...
// in a worker thread...
Lock.Enter;
try
NewList.Clear;
NewList.Add('test');
...
finally
Lock.Leave;
end;
// signal main UI thread that a new list is ready ...
...
// in the main UI thread...
private
MyListItems: TStringList; // or whatever you want to use to store your item data
...
begin
Lock.Enter;
try
MyListItems.Assign(NewList);
finally
Lock.Leave;
end;
ListView1.Items.Count := MyListItems.Count;
end;
procedure TMyForm.ListView1Data(Sender: TObject; Item: TListItem);
begin
Item.Caption := MyListItems[Item.Index];
...
end;
我想在后台刷新列表视图列表,为此我创建了一个临时 TListItems,但我无法将它分配给我的列表视图。如果我创建 TListItems 和 TListItem,则会发生访问冲突错误;
var
lis:TListItems;
li:TListItem;
begin
lis := TListItems.Create(nil);
try
li := TListItem.Create(nil);
li.Caption := 'test'; // at this line av occurs
lis.AddItem(li);
ListView1.Items.BeginUpdate;
try
ListView1.Items.Assign(lis);
finally
ListView1.Items.EndUpdate;
end;
finally
lis.Destroy();
end;
如果我在创建 TListItems 时使用 ListView1 作为所有者,则不会出现新行;
var
lis:TListItems;
li:TListItem;
begin
lis := TListItems.Create(ListView1);
try
li := TListItem.Create(lis);
li.Caption := 'test';
lis.AddItem(li);
ListView1.Items.BeginUpdate;
try
ListView1.Items.Assign(lis);
finally
ListView1.Items.EndUpdate;
end;
finally
lis.Destroy();
end;
所以我想在后台准备一个新列表并将其分配给列表视图,我该怎么做?
注意:准备列表需要很长时间,这就是我在后台准备的原因。 (我正在用线程填充列表并使用 TRTLCriticalSection 保护它)
TListItems
和 TListItem
与 TListView
密切相关,因此不能像您尝试的那样以独立方式使用。 TListItems
和 TListItem
都委托给 TListView
来处理他们的工作。
您在第一个示例中获得了 AV,因为没有分配 TListView
来处理该工作。
在你的第二个例子中,新的列表项没有正确显示,因为当你分配它的 Caption
时它还没有被添加到 ListView,所以 属性 setter更新。 AddItem()
不会将预先存在的 属性 值应用到新插入的列表项。必须使用单独的 属性 setter。
你必须首先使用TListItems.Add()
方法而不是直接调用AddItem()
,然后你可以根据需要修改新的TListItem
,例如:
var
NewList: TStringList;
Lock: TCriticalSection;
...
// in a worker thread...
Lock.Enter;
try
NewList.Clear;
NewList.Add('test');
...
finally
Lock.Leave;
end;
// signal main UI thread that a new list is ready ...
...
// in the main UI thread when the signal is received...
var
li: TListItem;
i: Integer;
begin
Lock.Enter;
try
ListView1.Items.BeginUpdate;
try
ListView1.Items.Clear;
for i := 0 to NewList.Count-1 do
begin
li := ListView1.Items.Add;
li.Caption := NewList[i];
...
end;
finally
ListView1.Items.EndUpdate;
end;
finally
Lock.Leave;
end;
end;
但是,正如 David H 在评论中所说,在虚拟模式下使用 ListView(将 OwnerData
属性 设置为 true
并使用 TListView.OnData...
事件)是处理这种情况的更好方法:
var
NewList: TStringList;
Lock: TCriticalSection;
...
// in a worker thread...
Lock.Enter;
try
NewList.Clear;
NewList.Add('test');
...
finally
Lock.Leave;
end;
// signal main UI thread that a new list is ready ...
...
// in the main UI thread...
private
MyListItems: TStringList; // or whatever you want to use to store your item data
...
begin
Lock.Enter;
try
MyListItems.Assign(NewList);
finally
Lock.Leave;
end;
ListView1.Items.Count := MyListItems.Count;
end;
procedure TMyForm.ListView1Data(Sender: TObject; Item: TListItem);
begin
Item.Caption := MyListItems[Item.Index];
...
end;