首先,我正在回答我自己的Q / A风格问题,所以我不一定需要任何人回答这个问题。这是我学到的东西,许多人可以利用这一点。
我有一个树视图,它包含许多不同的节点。每个节点在其Data
属性中都有一个对象,对象从一个主对象列表引用不同级别的层次结构,这些对象非常大(数千个项目)。一个节点表示此主列表对象上的特定属性,其中树允许用户选择节点以查看属于该特定选定类别的项目。
当填充树时,它变得非常耗时(在某些情况下为2分钟),因为每个节点需要遍历此大型列表中的每个项目,并查找此列表中属于任何给定节点的每个项目。因此,如果此树中有500个节点,则它将遍历此大型列表500次。总共有3个级别的层次结构 - 加载第二和第三级时会出现性能阻塞,但第一级是简单快速的。
现在没有任何选项可以提高数百次遍历此列表的性能。我想知道是否有任何已知的技巧来提高填充树视图的性能?
以下是目前的工作原理:
var
X: Integer;
N: TTreeNode;
O: TMyObject;
begin
for X := 0 to MyObjectList.Count - 1 do begin
O:= TMyObject(MyObjectList[X]); //Object which Node represents
N:= TreeView.Items.AddChild(nil, O.Caption);
N.Data:= O;
LoadNextLevel(N); //Populates child nodes by iterating through master list again
end;
end;
每个额外级别的类似方法。
PS - 第一级层次结构从其自己的单独列表(约50个对象)填充,而第二级和第三级从主列表中的这些数千个对象的属性填充。这就是为什么第一级加载很快,其余的很慢。
答案 0 :(得分:15)
如果您真的关心填充大量树视图的速度,您应该查看virtualTreeView(http://code.google.com/p/virtual-treeview/)。
它是一个开源树视图,专门设计为虚拟,并最大化速度/内存,适用于大型树视图
这是一个了不起的组成部分。
答案 1 :(得分:5)
树视图中有一个常见的技巧可以改善这种情况下的性能。刷新此树视图时,仅加载第一级层次结构,并且不必担心任何其他级别。相反,您可以在扩展每个节点时加载每个附加级别。这是如何做到的。
填充第一级时,而不是继续加载其每个子节点,而只是在其nil
属性中创建一个带有Data
指针的“虚拟”子节点 - 因为每个节点期望在Data
属性中有一个对象。然后,监视树视图的OnExpanding
事件。展开节点时,它将检查是否存在此“虚拟”子节点。如果是这样,那么它知道它需要加载子节点。
加载第一级层次结构时......
var
X: Integer;
N, N2: TTreeNode;
O: TMyObject;
begin
for X := 0 to MyObjectList.Count - 1 do begin
O:= TMyObject(MyObjectList[X]); //Object which Node represents
N:= TreeView.Items.AddChild(nil, O.Caption);
N.Data:= O;
N2:= TreeView.Items.AddChild(N, '');
N2.Data:= nil; //To emphasize that there is no object on this node
end;
end;
然后,为OnExpanding
...
procedure TForm1.TreeViewExpanding(Sender: TObject; Node: TTreeNode;
var AllowExpansion: Boolean);
var
N: TTreeNode;
begin
N:= Node.getFirstChild;
if N.Data = nil then begin
//Now we know this is a "dummy" node and needs to be populated with child nodes
N.Delete; //Delete this dummy node
LoadNextLevel(N); //Populates child nodes by iterating through master list
end;
end;
这个技巧的唯一缺点是,即使可能没有任何子节点,所有尚未展开的节点旁边都会有一个+
。如果是这种情况,那么当用户单击+
以展开节点时,子节点将被删除,+
消失,因此用户知道该节点中没有子节点。
此外,在BeginUpdate
中使用EndUpdate
和TreeView.Items
可以通过不执行GUI更新来提高性能,直到全部完成...
TreeView.Items.BeginUpdate;
try
//Refresh the tree
finally
TreeView.Items.EndUpdate;
end;