【问题标题】:Iterate recursively through nodes in a tree view?递归遍历树视图中的节点?
【发布时间】:2012-12-12 06:54:09
【问题描述】:

我有一个树视图,其中已经填充了来自另一个过程的文件/文件夹。我想逐一迭代树视图中的项目,从上到下按照确切的顺序进行。但是,与普通列表不同,我不能只使用一个简单的for 语句。我必须进入每个节点等。

我该怎么做?我希望有一种方法可以在不运行递归过程的情况下做到这一点。当我遍历这些项目时,我不一定关心当前关注的项目的父节点或子节点。我只需要能够在传递每个节点时读取它们的Data 属性,并在我通过它时突出显示树视图中的当前节点。对于此树视图中的每个项目,我将执行一些工作,并希望向用户直观地显示在此过程中当前选择了哪个项目。

【问题讨论】:

  • “我不能只使用一个简单的 for 语句” for 循环的递归函数/过程,在 for 循环 之后您对 Node.Data 属性进行操作,调用者将继续下一个节点等等...
  • 我说过我不能为此使用简单的 for 语句,因为树视图中没有项目索引或总节点数之类的东西。
  • 看来大卫找到了你的解决方案,而且还很干净......
  • @LURD VCL 已经过优化,因此通过索引的顺序访问是高效的。随机访问不是。
  • @LURD 我最近才意识到这一切。我一直使用GetNext。文档薄弱。

标签: delphi recursion treeview iteration


【解决方案1】:

事实上你可以使用for循环。

var
  Node: TTreeNode;
....
for Node in TreeView.Items do
  DoSomething(Node);

这是语法糖:

for i := 0 to TreeView.Items.Count-1 do
  DoSomething(TreeView.Items[i]);

就可读性而言,我推荐for/in 循环。

在不支持节点迭代器的旧 Delphi 版本中,您可能更喜欢使用 while 循环。

Node := TreeView.Items.GetFirstNode;
while Assigned(Node) do
begin
  DoSomething(Node);
  Node := Node.GetNext;
end;

我希望还有其他方法可以做到这一点。我知道的只有这些!


LU RD 提出了documentation 声明的有趣观察:

按索引访问树视图项目可能会耗费大量时间,尤其是当树视图包含许多项目时。为获得最佳性能,请尝试将您的应用程序设计为尽可能少地依赖树视图的项目索引。

这是非常正确的。对于随机访问,代码必须遍历树,从根开始,直到找到第 ith 节点。

但是,对顺序访问进行了优化。 Delphi 树视图包装器记住由索引定位的最后一个节点的索引。下次你请求一个与缓存节点的索引不超过一个的节点时,可以快速返回所需的节点。这是在TTreeNodes.GetNodeFromIndex 中实现的。

【讨论】:

  • NICE,我从来没有想过这是可能的。
  • @bummi 谢谢。 ;-) 你有没有研究过 Items[i] 是如何实现的?这是一项相当不错的工作!
  • 看看如果有人打电话会发生什么会很有趣,例如直接TreeView_InsertItem,绕过treeview,分别调用SendMessage(hwnd, TVM_INSERTITEM .....
  • @bummi 发生这种情况时缓存失效。
【解决方案2】:
var
 i:Integer;
begin
  for I := 0 to tv.Items.Count - 1 do
      begin
        Listbox1.Items.Add(tv.Items[i].Text +' SubItems: ' + IntToStr(tv.Items[i].Count))
      end;

end;

【讨论】:

  • 这只是第一层的层次结构,不是所有的子项。
  • @Jerry 不,这将它们全部列举出来
  • ...我很困惑,很抱歉草草下结论。
  • 如果需要,每个级别都有更多的迭代可能性。
  • 我很少使用任何类型的树或层次结构或任何递归。这是我需要小心的情况之一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 2018-07-12
  • 2014-03-11
  • 1970-01-01
  • 2020-08-15
  • 2012-03-21
  • 2017-05-11
相关资源
最近更新 更多