我想在后台刷新listview的列表,为此我创建了一个临时的TListItems,但是我无法将其分配给我的listview。如果我创建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;
所以我想在后台准备一个新列表并将其分配给listview,我该怎么办?
注意:准备列表需要很长时间,这就是为什么我在后台准备它。 (我通过线程填充列表,并使用TRTLCriticalSection保护列表)
答案 0 :(得分:1)
TListItems
和TListItem
与TListView
紧密相连,因此不能像您尝试的那样以独立方式使用。 TListItems
和TListItem
都委托给TListView
处理他们的工作。
在第一个示例中,您获得了AV,因为没有分配TListView
来处理工作。
在第二个示例中,新列表项未正确显示,因为在分配其Caption
时尚未将其添加到ListView,因此属性设置程序没有任何更新。并且AddItem()
不会将现有属性值应用于新插入的列表项。必须使用单个属性设置器代替。
您必须首先使用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;