The fundamental idea is that if something behind the scenes changes, the tree need to repainted. This means that the next time the tree draws itself, it will use the new underlying values.
If your tree is sitting there on screen:

You can simply call:
tvItems.Invalidate;
This tells Windows that the entire tree is now "invalid" and needs to be redrawn. I can represent this "invalid" region that will be updated the next time the tree paints itself:

And that's fine, correct, and will work perfectly adequately.
Performance improvements
A lot of times it's perfectly reasonable to force the entire tree to repaint all of itself.
But it's also possible to begin to optimize things. If you know that only a certain region of a Windows control is "invalid", then you could just invalidate that portion.
The Windows function to do that is InvalidateRect:
InvalidateRect(tvItems.Handle, Rect(13, 18, 30, 38), True);
That will invalidate a 30x38 square at 13,18:

In fact all TWinControl.Invalidate
is doing is turning around and calling the Windows InvalidateRect function:
//true means to also trigger an erase of the background
InvalidateRect(Self.Handle, Self.BoundsRect, True);
There may not be much use for such a strange rectangle to be invalidated. But you can probably imagine other rectangles you'd like to be invalidated.
Invalidating nodes
Windows doesn't realize it, but your control represents a tree, and the tree and nodes. And there might be times when you want to invalidate the rectangle of a "node":

Rather than you having to figure out the coordinates and size of a node, the
TVirtualTree already provides you a handy method to invalidate a node:
function InvalidateNode(Node: PVirtualNode): TRect; virtual;
// Initiates repaint of the given node and returns the just invalidated rectangle.
so:
tvItems.InvalidateNode(someNode);
It also provides a method to invalidate a node and all its children:
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).
This is useful when your tree has children:

You can invalidate the parent node and all the children that now need to be updated with the new numbers:
tvItems.InvalidateChildren(someNode, True);
And other helper methods
The Virtual Tree has other helpful methods that:
- get a certain interesting rectangle to invalidate
- call Windows.InvalidateRect
That is:
InvalidateToBottom(Node: PVirtualNode);
Initiates repaint of client area starting at given node. If this node is not visible or not yet initialized then nothing happens.
TBaseVirtualTree.InvalidateColumn(Column: TColumnIndex);
Invalidates the client area part of a column.
Invalidating vs Repaint
Your other question is in regards to the confusion over the difference between:
When you invalidate a rectangle (e.g. an entire form, an entire control, or some smaller rectangle such as a node, node and its children, or a column) you are telling Windows that it needs to ask the control to paint self. That is:
the pixels on screen are now invalid and must be repainted
This will happen the next time the tree is asked to paint itself. Windows is message-based. And as your application runs, it processes messages, including a WM_PAINT
message. When the VirtualTree
gets a WM_PAINT
message, it paints the portions it was asked to repaint.
This means that for any and all painting to happen, you have to be processing messages - i.e. you have to let your program go "idle".
If you sit there is a busy loop, never letting your code exit:
procedure TForm1.Button1Click(Sender: TObject);
begin
while (true) do
begin
tvItems.Invalidate;
Sleep(100);
end;
end;
The loop never ends, and the tree is never given a chance to actually paint itself.
Delphi's horrible Repaint hack
Delphi has a horrible hack that forces a control to be painted.
- it pretends that it's Windows asking a control to paint itself
- and then jumps directly to the control's paint routine
This means that the control will paint itself, even though it's not received a WM_PAINT
message from Windows - it just does the scribbling.
procedure TForm1.Button1Click(Sender: TObject);
begin
while (true) do
begin
tvItems.Repaint; //force the control to repaint itself
Sleep(100);
end;
end;
It's an ugly hack because:
- in the first case our code wasn't processing Windows messages
- in the revised case we're still not doing the right thing, and trying to use a hammer to screw in a screw
The correct solution in these cases is to have a background thread. And have the background thread signal the main application that it needs to invalidate the tree. The main program will then receive a WM_PAINT
message and draw itself as normal.