Delphi: changing focus after removing a node from a virtual row tree

I have a component like TVirtualStringTree (let's call it VST ). It has nodes in the form of a list, i.e. All nodes are on the same level. I want to change focus after deleting the node (using the DeleteNode method), and I used the OnFreeNode event:

 procedure TMyForm.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); var NewFocus: PVirtualNode; begin NewFocus := VST.GetNext(Node); if not Assigned(newFocus) then NewFocus := VST.GetPrevious(Node); if Assigned(NewFocus) then begin VST.FocusedNode := NewFocus; VST.Selected[NewFocus] := True end; end; 

I also want the change to cause some reactions, for example. set the Enabled property of the button:

 procedure TMyForm.VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); begin btn1.Enabled := Assigned(Node); end; 

But there are some problems with the solution. For example, when I close the form using the Cancel button (the form is opened using the ShowModal method), the nodes are freed, VSTFocusChanged starts, and later throws an exception due to the nil button. Of course, I can check if the button is assigned, but is there a more elegant solution for changing focus after deleting the node without this unwanted effect (and without other unwanted effects)?

+7
delphi focus tvirtualstringtree
source share
1 answer

Is there a built-in way to always select node?

Yes there is. Remove the code from these events and enable the toAlwaysSelectNode option in the TreeOptions.SelectionOptions tree setting (for example, enable it in the IDE). A comment on this option says:

If this flag is set to true, the tree tries to always have a node selected.

Including the removal of node.


How to safely update management status controlled by external management from a VT event?

The problem you are facing is that you focused the node manually from the OnFreeNode event, which in turn raised the OnFocusChanged event. And since nodes are also freed when the control is destroyed and this button was destroyed earlier, you are trying to access the destroyed control. To avoid this in the future, you can use RTL actions because there are many events that VT fires, even when it has csDestroying state (including an event like OnStructureChange ), and actions are one safe workaround.

Something like this should work safely (I'm not a fan of the OnUpdate event):

 procedure TMyForm.VSTStructureChange(Sender: TBaseVirtualTree; Node: PVirtualNode; Reason: TChangeReason); begin { ActionDeleteNode is assigned to the button Action property; SelectedCount is a bit paranoic here because if you use the toAlwaysSelectNode option, at least one node should be always selected, so RootNodeCount > 0 could do the same here } ActionDeleteNode.Enabled := Sender.SelectedCount > 0; end; 

Without RTL actions, you can safely update this button state, for example. immediately after the action, for example, after removing the node:

 VST.DeleteNode(VST.FocusedNode); ButtonDeleteNode.Enabled := VST.SelectedCount > 0; 

But with this, you can get out of sync and write more code. Therefore, using RTL actions is what I would prefer.

+3
source share

All Articles