Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 我应该如何更新虚拟树视图中的节点?_Delphi_Virtualtreeview - Fatal编程技术网

Delphi 我应该如何更新虚拟树视图中的节点?

Delphi 我应该如何更新虚拟树视图中的节点?,delphi,virtualtreeview,Delphi,Virtualtreeview,我正在使用DelphiXE3和虚拟树视图 我想用虚拟树视图来实现一个树,当点击开始按钮时,程序会递归地搜索一个驱动器下的所有文件和文件夹,然后将它们逐个添加到树中,就像Windows资源管理器一样。此外,应该有一个数字指示文件夹下的文件和子文件夹的数量,使用如下静态文本: 在我的实践中,我发现有时数字没有正确更新 因此,每当更改文件/子文件夹的数量时,我认为以下方法可以刷新节点: 调用tviitems.ChangePNode更新节点 调用TVTItems.InvalidateNode 调用tvi

我正在使用DelphiXE3和虚拟树视图

我想用虚拟树视图来实现一个树,当点击开始按钮时,程序会递归地搜索一个驱动器下的所有文件和文件夹,然后将它们逐个添加到树中,就像Windows资源管理器一样。此外,应该有一个数字指示文件夹下的文件和子文件夹的数量,使用如下静态文本:

在我的实践中,我发现有时数字没有正确更新

因此,每当更改文件/子文件夹的数量时,我认为以下方法可以刷新节点:

调用tviitems.ChangePNode更新节点

调用TVTItems.InvalidateNode

调用tviitems.repainnodepnode

调用tviitems.UpdateAction


但是,1是无法调用的受保护方法。2和3都可以,但不知道哪一个更适合更新。4没有文档记录,也不知道如何称呼它。

基本思想是,如果幕后发生了变化,则需要重新绘制树。这意味着下次树绘制自身时,它将使用新的基础值

如果您的树位于屏幕上:

您只需拨打:

tvItems.Invalidate;
这会告诉Windows整个树现在无效,需要重新绘制。我可以表示此无效区域,该区域将在下次树自身绘制时更新:

这是很好的,正确的,并且将非常有效

性能改进 很多时候,强迫整棵树都重新粉刷自己是完全合理的

但也有可能开始优化事情。如果您知道只有Windows控件的某个区域无效,则可以使该部分无效

Windows的功能是:

这将使30x38正方形在13,18处失效:

事实上,TWinControl.Invalidate所做的一切都是调转并调用Windows Invalidate函数:

//true means to also trigger an erase of the background
InvalidateRect(Self.Handle, Self.BoundsRect, True); 
这样一个奇怪的矩形无效可能没有多大用处。但是你可以想象其他的矩形,你希望它无效

失效节点 Windows没有意识到这一点,但您的控件表示一棵树,以及树和节点。有时您可能希望使节点的矩形无效:

您不必计算节点的坐标和大小 TVirtualTree已经为您提供了一种使节点无效的简便方法:

因此:

它还提供了使节点及其所有子节点无效的方法:

当您的树有子树时,这非常有用:

您可以使父节点和现在需要使用新编号更新的所有子节点无效:

tvItems.InvalidateChildren(someNode, True);
和其他辅助方法 虚拟树还有其他有用的方法:

获取某个有趣的矩形以使其无效 调用Windows.com 即:

InvalidateToBottomNode:PVirtualNode; 从给定节点开始重新绘制客户端区域。如果此节点不可见或尚未初始化,则不会发生任何事情。 TBaseVirtualTree.InvalidateColumnColumn:TColumnIndex;使列的工作区部分无效。 失效与重新喷漆 你的另一个问题是关于对以下区别的混淆:

无效 重涂 当您使矩形(例如整个窗体、整个控件或一些较小的矩形(例如节点、节点及其子节点)或列)无效时,您告诉Windows它需要要求控件自行绘制。即:

屏幕上的像素现在无效,必须重新绘制

这将发生在下一次树被要求画自己的时候。Windows是基于消息的。当应用程序运行时,它会处理消息,包括WM_PAINT消息。当VirtualTree收到WM_PAINT消息时,它会绘制要求重新绘制的部分

这意味着,要进行任何和所有的绘制,您必须处理消息-即,您必须让您的程序闲置

如果您坐在忙碌的循环中,永远不要让代码退出:

procedure TForm1.Button1Click(Sender: TObject);
begin
   while (true) do 
   begin
      tvItems.Invalidate;
      Sleep(100);
   end;
end;
循环永远不会结束,树也永远没有机会真正画自己

德尔福可怕的重新油漆黑客 Delphi有一个可怕的黑客程序,它迫使一个控件被绘制

它假装是Windows要求控件自行绘制 然后直接跳到控件的绘制例程 这意味着控件将自己绘制,即使它没有从Windows收到WM_绘制消息-它只是进行涂鸦

procedure TForm1.Button1Click(Sender: TObject);
begin
   while (true) do 
   begin
      tvItems.Repaint; //force the control to repaint itself
      Sleep(100);
   end;
end;
这是一个丑陋的黑客行为,因为:

在第一种情况下,我们的代码没有处理Windows消息 在修改后的案例中,我们仍然没有做正确的事情,并试图使用锤子拧入螺钉 在这些情况下,正确的解决方案是使用后台线程。并让后台线程向它需要使树失效的主应用程序发送信号。主要
然后,程序将收到WM_PAINT消息,并按正常方式绘制自身。

基本思想是,如果幕后发生变化,则需要重新绘制树。这意味着下次树绘制自身时,它将使用新的基础值

如果您的树位于屏幕上:

您只需拨打:

tvItems.Invalidate;
这会告诉Windows整个树现在无效,需要重新绘制。我可以表示此无效区域,该区域将在下次树自身绘制时更新:

这是很好的,正确的,并且将非常有效

性能改进 很多时候,强迫整棵树都重新粉刷自己是完全合理的

但也有可能开始优化事情。如果您知道只有Windows控件的某个区域无效,则可以使该部分无效

Windows的功能是:

这将使30x38正方形在13,18处失效:

事实上,TWinControl.Invalidate所做的一切都是调转并调用Windows Invalidate函数:

//true means to also trigger an erase of the background
InvalidateRect(Self.Handle, Self.BoundsRect, True); 
这样一个奇怪的矩形无效可能没有多大用处。但是你可以想象其他的矩形,你希望它无效

失效节点 Windows没有意识到这一点,但您的控件表示一棵树,以及树和节点。有时您可能希望使节点的矩形无效:

您不必计算节点的坐标和大小 TVirtualTree已经为您提供了一种使节点无效的简便方法:

因此:

它还提供了使节点及其所有子节点无效的方法:

当您的树有子树时,这非常有用:

您可以使父节点和现在需要使用新编号更新的所有子节点无效:

tvItems.InvalidateChildren(someNode, True);
和其他辅助方法 虚拟树还有其他有用的方法:

获取某个有趣的矩形以使其无效 调用Windows.com 即:

InvalidateToBottomNode:PVirtualNode; 从给定节点开始重新绘制客户端区域。如果此节点不可见或尚未初始化,则不会发生任何事情。 TBaseVirtualTree.InvalidateColumnColumn:TColumnIndex;使列的工作区部分无效。 失效与重新喷漆 你的另一个问题是关于对以下区别的混淆:

无效 重涂 当您使矩形(例如整个窗体、整个控件或一些较小的矩形(例如节点、节点及其子节点)或列)无效时,您告诉Windows它需要要求控件自行绘制。即:

屏幕上的像素现在无效,必须重新绘制

这将发生在下一次树被要求画自己的时候。Windows是基于消息的。当应用程序运行时,它会处理消息,包括WM_PAINT消息。当VirtualTree收到WM_PAINT消息时,它会绘制要求重新绘制的部分

这意味着,要进行任何和所有的绘制,您必须处理消息-即,您必须让您的程序闲置

如果您坐在忙碌的循环中,永远不要让代码退出:

procedure TForm1.Button1Click(Sender: TObject);
begin
   while (true) do 
   begin
      tvItems.Invalidate;
      Sleep(100);
   end;
end;
循环永远不会结束,树也永远没有机会真正画自己

德尔福可怕的重新油漆黑客 Delphi有一个可怕的黑客程序,它迫使一个控件被绘制

它假装是Windows要求控件自行绘制 然后直接跳到控件的绘制例程 这意味着控件将自己绘制,即使它没有从Windows收到WM_绘制消息-它只是进行涂鸦

procedure TForm1.Button1Click(Sender: TObject);
begin
   while (true) do 
   begin
      tvItems.Repaint; //force the control to repaint itself
      Sleep(100);
   end;
end;
这是一个丑陋的黑客行为,因为:

在第一种情况下,我们的代码没有处理Windows消息 在修改后的案例中,我们仍然没有做正确的事情,并试图使用锤子拧入螺钉
在这些情况下,正确的解决方案是使用后台线程。并让后台线程向它需要使树失效的主应用程序发送信号。然后,主程序将收到WM_PAINT消息并正常绘制。

非常感谢您的精彩详细回答!这真的很有帮助!如果我理解正确,1。建议使用“无效”而不是“重新绘制”。2.TVTItems.InvalidateNode和TVTItems.RepainNode的工作原理与TVTItems.Invalidate和TVTItems.Repain类似,只是它们用于特定节点。TVTItems.RepainNode将强制节点重新绘制,而不是发布WM_PAINT消息。@lanBoyd,非常感谢您的精彩详细回答!这真的很有帮助!如果我理解正确,1。建议使用“无效”而不是“重新绘制”。2.TVTItems.InvalidateNode和TVTItems.RepainNode的工作原理与TVTItems.Invalidate和TVTItems.Repain类似,只是它们用于特定节点。tvItems.RepainNode将强制节点重新绘制,而不是发布WM_PAINT消息。@lanBoyd,谢谢 多亏了