Reputation: 1824
I have Virtual Treeview and I use OnClick to execute code, when user clicks on node. In order for the same code is executed also when user uses keyboard to move from node to node, I use OnFocusChanged. In OnFocusChanged I call OnClick, so it is always same code executed, of course.
So, when a node is selected and user clicks on another node, both events are called OnClick and OnFocusChanges... and since OnFocusChanged calls OnClick, I use a little trick to avoid double executino of OnClick. I use flag to set to ignore 2nd call of OnClick.
Here is the code - OnFocusChanged:
procedure TForm1.VTVFocusChanged(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex);
begin
gTVFocusHasJustChanged_SkipClickEvent := false; // enable executing OnClick code
VTVClick(Sender);
gTVFocusHasJustChanged_SkipClickEvent := True; // disable executing OnClick code
end;
And here is OnClick:
procedure TForm1.VTVClick(Sender: TObject);
var
Data: ^rTreeData;
begin
// skip second OnClick call!
if gTVFocusHasJustChanged_SkipClickEvent then
begin
gTVFocusHasJustChanged_SkipClickEvent := false;
Exit;
end;
... // code to be executed when node selected
end;
This works as expected, either user clicks on node or moves with keyboard.
BUT, Is there better way to do this, easier to maintain or just makes more sense?
EDIT:
I think I need to add a little more info. Only specific code is executed when user selects node. Either with mouse, keyboard, if it was focused or not, already selected one node before and now selecting new one... basically in any and all occurrences, only specific code needs to be executed. I chose to use OnClick method where I have this code, I could use another function that gets called from OnClick, but that is practically the same. I do not execute different code based on condition of what happened, either it was a click, it was a keyboard move... all the same, no distinction between where the code was fired from. I hope this makes more sense of what is going on and provides more info where I need help.
EDIT #2:
Update on my progress: I started moving all my code from OnClick
into separate procedures, which improves maintainability and easier execution while node is selected (Mouse click or with keyboard) or under other circumstances. The answer below and comments gave me nudge into right direction that OnClick
is not the right place where code that is not based on OnClick
event should be executed.
Upvotes: 0
Views: 1451
Reputation: 464
The main idea is use global selected Node for every VirtualTree.
Here is the code :
TForm1 = class(TForm)
..........
private
fselectedVTNode : PVirtualNode; // used as global selected node for VTV
..........
public
..........
end;
//========== Event for VTV.OnFocusChanged ===============
procedure TForm1.VTVFocusChanged(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex);
var
Data: ^rTreeData;
begin
if (fselectedVTNode <> Node) then begin
fselectedVTNode := Node;
// ....... code to be executed when node selected
end;
end;
//========== Event for VTV.OnFreeNode ===============
procedure TForm1.VTVFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
if fselectedVTNode = Node then
fselectedVTNode := nil;
// .......code to be executed when node freed
end;
//========== Event for VTV.OnEnter ===============
procedure TForm1.VTVEnter(Sender: TObject);
var
VT:TBaseVirtualTree;
begin
fselectedVTNode := nil;
VT:=TBaseVirtualTree(Sender);
VTVFocusChanged(VT, VT.FocusedNode, VT.FocusedColumn);
end;
Upvotes: 3