gpt4 book ai didi

delphi - 我应该如何在Virtual TreeView中更新节点?

转载 作者:行者123 更新时间:2023-12-02 17:52:58 25 4
gpt4 key购买 nike

我正在使用Delphi XE3和Virtual TreeView。

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

VirtualTreeView - different color of text in the same node

在实施过程中,我发现有时该号码未正确更新。

因此,我认为只要文件/子文件夹的数量发生更改,就可以通过以下方式刷新节点:


调用tvItems.Change(PNode)更新节点。
调用tvItems.InvalidateNode(PNode)。
调用tvItems.RepaintNode(PNode)。
调用tvItems.UpdateAction。


但是,1是无法调用的受保护方法。 2和3都可以,但是不知道哪个更新更好。 4没有记录,也不知道如何调用。

最佳答案

基本思想是,如果幕后的某些事物发生变化,则需要对树进行重新粉刷。这意味着树下一次绘制自身时,将使用新的基础值。

如果您的树坐在屏幕上:

enter image description here

您可以简单地致电:

tvItems.Invalidate;


这告诉Windows,整个树现在“无效”,需要重绘。我可以代表这个“无效”区域,该区域将在下次树绘制自身时进行更新:

enter image description here

很好,正确,可以正常运行。

性能提升

很多时候,强迫整棵树重新粉刷整个树是完全合理的。

但是也可以开始进行优化。如果您知道Windows控件的仅某个区域是“无效”的,则可以使该部分无效。

Windows功能是 InvalidateRect

InvalidateRect(tvItems.Handle, Rect(13, 18, 30, 38), True); 


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

enter image description here

实际上,所有 TWinControl.Invalidate所做的只是转过头并调用Windows InvalidateRect函数:

//true means to also trigger an erase of the background
InvalidateRect(Self.Handle, Self.BoundsRect, True);


使这种奇怪的矩形无效可能没有太多用处。但是您可能会想像其他要失效的矩形。

使节点无效

Windows没有意识到这一点,但是您的控件代表一棵树,以及树和节点。有时您可能想使“节点”的矩形无效:

enter image description here

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

function InvalidateNode(Node: PVirtualNode): TRect; virtual;
// Initiates repaint of the given node and returns the just invalidated rectangle.


所以:

tvItems.InvalidateNode(someNode);


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

procedure TBaseVirtualTree.InvalidateChildren(Node: PVirtualNode; Recursive: Boolean);
// Invalidates Node and its immediate children.
// If Recursive is True then all grandchildren are invalidated as well.
// The node itself is initialized if necessary and its child nodes are created (and initialized too if
// Recursive is True).


当您的树上有孩子时,这很有用:

enter image description here

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

tvItems.InvalidateChildren(someNode, True);


和其他辅助方法

虚拟树还有其他有用的方法,它们可以:


得到一个有趣的矩形来使
呼叫Windows.InvalidateRect


那是:


InvalidateToBottom(Node: PVirtualNode);
从给定节点开始重新绘画工作区。如果此节点不可见或尚未初始化,则不会发生任何事情。
TBaseVirtualTree.InvalidateColumn(Column: 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_PAINT消息-它也只是在进行绘制。

procedure TForm1.Button1Click(Sender: TObject);
begin
while (true) do
begin
tvItems.Repaint; //force the control to repaint itself
Sleep(100);
end;
end;


这是一个丑陋的hack,因为:


在第一种情况下,我们的代码没有处理Windows消息
在修改后的案例中,我们仍然没有做正确的事,并尝试使用锤子拧入螺丝


在这些情况下,正确的解决方案是使用后台线程。并让后台线程向主应用程序发出信号,表明它需要使树无效。然后,主程序将收到一条 WM_PAINT消息,并照常进行绘制。

关于delphi - 我应该如何在Virtual TreeView中更新节点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58110531/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com