Let me try to explain my situation:
I'm using VirtualTree as a grid, and every time when the OnFocusChanged event is fired, and the active focus node was changed, I have a synchronous operation which may take 0-1 sec which blocks the main Thread (sometimes more).
I can live with this.
For now, I can't move this logic to a worker thread.
My problem happens when I use the arrows keys to move up and down in the grid, and the focus node is changing rapidly. It is not smooth because of the blocking.
So I tried to use a Post message like:
procedure TForm1.VTFocusChanged(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex);
begin
// if (T = 0) or (GetTickCount - T > 1000) then
begin
Sender.InvalidateNode(Node);
PostMessage(Handle, UM_VT_CHANGED, Integer(Sender), Integer(Node));
end;
end;
procedure TForm1.UMVTChanged(var Message: TMessage);
var
Tree: TBaseVirtualTree;
Node: PVirtualNode;
begin
// T := GetTickCount;
Tree := TBaseVirtualTree(Message.WParam);
Node := PVirtualNode(Message.LParam);
...
// DO the job!
end;
This helps a little, but still I realize I need some "Idle" mechanism. So if I move arrows up and down my working process will only be triggered when the VirtualTree is Idle for 100 ms or so. I realize I need to use some timer or maybe "eat" the Post messages and process only the last one, but I can't figure how to do it. I tried many variations with TTimer/GetTickCount and it seems I'm really messing something so trivial.
I solved this with a TTimer. Could not think of a better way. Here is the basic idea and it could be improved:
procedure TForm1.VTFocusChanging(Sender: TBaseVirtualTree; OldNode,
NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
var Allowed: Boolean);
begin
FocusTimer.Enabled := False;
end;
procedure TForm1.VTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
begin
FLastNode := Node;
FocusTimer.Interval := 250;
FocusTimer.Enabled := True;
end;
procedure TForm1.FocusTimer_OnTimer(Sender: TObject);
begin
FocusTimer.Enabled := False;
if FLastNode = nil then Exit;
PostMessage(Handle, UM_VT_CHANGED, Integer(VT), Integer(FLastNode));
end;