如何提高填充大树视图的性能? [英] How to improve performance of populating a massive tree view?

查看:96
本文介绍了如何提高填充大树视图的性能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我要回答自己的问题Q/A风格,因此我并不一定需要任何人来回答.这是我学到的东西,许多人可以利用它.

First of all I am answering my own question Q/A style, so I don't necessarily need anyone to answer this. It's something I've learned and many can make use of this.

我有一个树视图,其中包含许多不同的节点.每个节点在其Data属性中都有一个对象,该对象从一个对象的主列表中引用不同的层次结构,该列表非常大(成千上万个项目).一个节点代表此主要列出的对象上的特定属性,该树允许用户选择一个节点来查看属于该特定选定类别的那些项.

I have a tree view which consists of many different nodes. Each node has an object behind it in its Data property, and the objects refer to different levels of hierarchy from one master list of objects, which is quite large (many thousands of items). One node represents a specific property on this main listed object, where the tree allows the user to select a node to view those items which fall under that specific selected category.

在填充树时,它变得非常耗时(在某些情况下为2分钟),因为每个节点都需要遍历此大列表中的每个项目并找到该列表中的每个项目都落在任何给定节点下.因此,如果此树中有500个节点,则将遍历此大列表500次.共有3个层次结构-加载第二个和第三个层次时会出现性能瓶颈,但是第一个层次既简单又快速.

When the tree is being populated, it becomes extremely time consuming (in some cases 2 minutes), because each node needs to iterate through every item in this large list and find each item in this list which falls under any given node. Therefore, if there are to be 500 nodes in this tree, then it iterates through this large list 500 times. There are a total of 3 levels of hierarchy - the performance choke comes in when loading the second and third levels, but the first level is simple and quick.

现在没有任何选项可以提高对该列表进行数百次迭代的性能.我想知道是否有任何已知的技巧可以提高填充树状视图的性能?

Now there aren't any options to improve the performance of iterating through this list hundreds of times. What I'm wondering is are there any known tricks to improve the performance of populating the tree view?

这是当前的工作方式:

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;

每个其他级别都有类似的方法.

And a similar method for each additional level.

PS-层次结构的第一级从其自身的单独列表(约50个对象)填充,而第二级和第三级则从主列表中成千上万个对象的属性填充.这就是为什么第一级加载速度快,而其他级别加载速度慢的原因.

PS - The first level of hierarchy is populated from a separate list of its own (about 50 objects) whereas the second and third levels are populated from the properties of these many thousands of objects in a master list. This is why the first level loads quickly, and the rest is slow.

推荐答案

在这种情况下,树视图中有一个常见的技巧可以提高性能.刷新此树视图时,仅加载层次结构的第一级,而不用担心任何其他层次.相反,您可以在扩展每个节点时加载每个其他级别.这是这样做的方法.

There is a common trick in tree views to improve the performance in this type of situation. When you refresh this tree view, only load the first level of hierarchy, and don't worry about any further levels. Instead, you can load each additional level at the time of expanding each node. Here's how to do it.

当您填充第一级时,与其继续加载其每个子节点,不如继续创建1个虚拟"子节点,并在其Data属性中使用nil指针-因为每个节点都应该具有还是Data属性中的对象.然后,监视树视图的OnExpanding事件.扩展节点时,它将检查该虚拟"子节点是否存在.如果是这样,那么它知道需要加载子节点.

When you populate the first level, rather than continuing with loading each of its child nodes, instead just create 1 "dummy" child node with a nil pointer in its Data property - since each node is expected to have an object in the Data property anyway. Then, monitor the OnExpanding event of the tree view. When a node is expanded, it will check to see if this "dummy" child node exists or not. If so, then it knows it needs to load the child nodes.

在加载第一级层次结构时...

When the first level of hierarchy is loaded...

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;

此技巧的唯一缺点是,即使可能没有任何子节点,所有尚未扩展的节点都将在其旁边带有+.如果是这种情况,那么当用户单击+展开节点时,子节点将被删除,而+消失,因此用户知道该节点内没有子节点.

The only disadvantage to this trick is that all nodes which have not yet been expanded will have a + next to them, even though there may not be any child nodes. If this is the case, then when the user clicks the + to expand a node, the child node gets deleted and the + disappears so the user knows there are no child nodes within that node.

此外,在TreeView.Items中使用BeginUpdateEndUpdate可以提高性能,因为直到完成所有操作后才执行GUI更新...

Also, using BeginUpdate and EndUpdate in TreeView.Items improves performance by not performing GUI updates until it's all done...

TreeView.Items.BeginUpdate;
try
  //Refresh the tree
finally
  TreeView.Items.EndUpdate;
end;

这篇关于如何提高填充大树视图的性能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆