1

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.

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
ZigiZ
  • 2,480
  • 4
  • 25
  • 41
  • Perhaps [`like this`](http://pastebin.com/0s0kRMKa) ? – TLama Jan 08 '14 at 09:44
  • @TLama, not seem to be working for me. the PostMessage is not send all the time when the node is "idle" (`if GetTickCount - FLastTick > 1000 then` is false). so if I move down up and up rapidly back to the first node, It sometimes get posted and sometimes not. but it's close to what I need. again I can't put my mind on the problem while debugging :( – ZigiZ Jan 08 '14 at 10:03
  • It should work precisely. The message won't be posted more frequently than in one second. The only thing you were missing in your attempt is that you weren't updating your `T` variable with the current tick count value. – TLama Jan 08 '14 at 10:39
  • @TLama, Yes but the last focused/landing node so to speek (after moving down + up) is focused in between the gap of 100 ms so the `if` is false. – ZigiZ Jan 08 '14 at 11:52

1 Answers1

2

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;
ZigiZ
  • 2,480
  • 4
  • 25
  • 41