ala*_*ncc 1 delphi virtualtreeview
我正在使用 Delphi XE3 和 Virtual TreeView。
我想用Virtual TreeView来实现一棵树,当点击“开始”按钮时,程序会递归搜索一个驱动器下的所有文件和文件夹,然后将它们一一添加到树中,就像Windows资源管理器一样。此外,应该有一个数字指示文件夹下的文件和子文件夹的数量,使用静态文本如下:
VirtualTreeView - 同一节点中不同颜色的文本
在我看来,我发现有时数字没有正确更新。
因此,每当文件/子文件夹的数量发生变化时,我认为可以通过以下方式刷新节点:
调用 tvItems.Change(PNode) 来更新节点。
调用 tvItems.InvalidateNode(PNode)。
调用 tvItems.RepaintNode(PNode)。
调用 tvItems.UpdateAction。
但是,1 是无法调用的受保护方法。2 和 3 都可以,但不知道哪个更适合更新。4 没有记录,不知道如何称呼它。
基本思想是,如果幕后发生某些变化,则需要重新绘制树。这意味着下次树绘制自身时,它将使用新的基础值。
如果您的树坐在屏幕上:
您可以简单地调用:
tvItems.Invalidate;
Run Code Online (Sandbox Code Playgroud)
这告诉 Windows整个树现在“无效”并且需要重新绘制。我可以表示这个“无效”区域,它将在下次树绘制自身时更新:
这很好,正确,并且可以完美地工作。
很多时候,这是完全合理的,迫使整个树重绘所有的本身。
但也可以开始优化事物。如果您知道只有 Windows 控件的某个区域是"invalid",那么您可以使该部分无效。
执行此操作的 Windows 函数是InvalidateRect:
InvalidateRect(tvItems.Handle, Rect(13, 18, 30, 38), True);
Run Code Online (Sandbox Code Playgroud)
这将使 13,18 处的 30x38 正方形无效:
事实上TWinControl.Invalidate,所做的就是转身并调用 Windows InvalidateRect函数:
//true means to also trigger an erase of the background
InvalidateRect(Self.Handle, Self.BoundsRect, True);
Run Code Online (Sandbox Code Playgroud)
这样一个奇怪的矩形无效可能没有多大用处。但是您可能可以想象其他您希望无效的矩形。
Windows 没有意识到这一点,但您的控件代表一棵树,以及树和节点。有时您可能希望使“节点”的矩形无效:
您不必弄清楚节点的坐标和大小, TVirtualTree已经为您提供了一个方便的方法来使节点无效:
function InvalidateNode(Node: PVirtualNode): TRect; virtual;
// Initiates repaint of the given node and returns the just invalidated rectangle.
Run Code Online (Sandbox Code Playgroud)
所以:
tvItems.InvalidateNode(someNode);
Run Code Online (Sandbox Code Playgroud)
它还提供了一种使节点及其所有子节点无效的方法:
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).
Run Code Online (Sandbox Code Playgroud)
当您的树有孩子时,这很有用:
您可以使父节点和现在需要使用新数字更新的所有子节点无效:
tvItems.InvalidateChildren(someNode, True);
Run Code Online (Sandbox Code Playgroud)
虚拟树还有其他有用的方法:
那是:
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;
Run Code Online (Sandbox Code Playgroud)
循环永远不会结束,树也永远不会有机会实际绘制自己。
Delphi 有一个可怕的 hack,它强制绘制控件。
这意味着控件将自行绘制,即使它没有收到WM_PAINT来自 Windows的消息 - 它只是进行涂鸦。
procedure TForm1.Button1Click(Sender: TObject);
begin
while (true) do
begin
tvItems.Repaint; //force the control to repaint itself
Sleep(100);
end;
end;
Run Code Online (Sandbox Code Playgroud)
这是一个丑陋的黑客,因为:
在这些情况下,正确的解决方案是拥有一个后台线程。并让后台线程通知主应用程序它需要使树无效。然后主程序将收到一条WM_PAINT消息并照常绘制自己。
| 归档时间: |
|
| 查看次数: |
519 次 |
| 最近记录: |