2
votes

I have VST with MultiSelect option enabled. How can I retrieve the list of selected nodes in VirtualStringTree when the selection changes via keyboard events?

I tried using the below code in the OnFocusChanged event

procedure TForm1.UpdateSelection(VST: TVirtualStringTree);
Var
  NodeArray: TNodeArray;
  NodeData: PNodeData;
  I: Integer;
begin
  Memo1.Clear;

  NodeArray := VST.GetSortedSelection(False);
  For I := Low(NodeArray) to High(NodeArray) do
  Begin
    NodeData := VST.GetNodeData(NodeArray[I]);
    Memo1.Lines.Add(NodeData.Caption);
  End;
end;

procedure TForm1.VST1FocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
    Column: TColumnIndex);
begin
  UpdateSelection(VST1);
end;

This works fine if I use the mouse and shift key, however, if I use the keyboard, i.e select node, then press shift and then down arrow to select multiple nodes, the selection returns the full list - 1.

This seems like a bug? Any ideas on how to get the full selection when using the keyboard?

2
It would be good if you include the used Delphi and VST version in your question.Joachim Marder
I found the same problem to occur in Delphi 7 VT v5, and Berlin 1.0 VT v6RaelB
Focused node and selected nodes are something different,if you need the selection (especially in case of multi-select), do not use focus events, but selection event.Joachim Marder

2 Answers

3
votes

I can also reproduce this behavior (D5, VT ver 4.5.5). looks like a bug to me, and I'll explain why:

Seems like the keyboard event(s) calls FocusChanged but does not change the internal FSelectedCount at the moment FocusChanged event is triggered. if you look at the code of GetSortedSelection, the first line is SetLength(Result, FSelectionCount); and if you test VST1.SelectionCount property it is set to the actual selection count - 1 (as you describe) or if you press SHIFT-END the previous value remains.

I have never noticed this in my own app because I use a delayed action via PostMessage in this specific event. this results the correct internals when the event handler exits. this could be one solution.

However, the proper solution which I believe is the correct way, is to handle the selection in the OnChange event handler - the selection could be change regardless of a focus node change.

1
votes

There are OnAddToSelection and OnRemoveFromSelection events which are meant to track changes in selection, I quess you should use these instead of OnFocusChanged event.

Did a quick test and it seems that when OnAddToSelection fires the GetSortedSelection method returns the array of nodes already selected and the node to be selected (or added to the selection) as Node argument.

When OnRemoveFromSelection fires the GetSortedSelection method returns the array of selected nodes and Node parameter is the node about to be removed from the selection. So you could say that the events are not competely "symmetrical".

When GetSortedSelection method is used in OnRemoveFromSelection the app indeed AVs on exit. I would say this is a bug in VT. Seting VT.OnRemoveFromSelection := nil; in form's OnDestroy handler seems to fix it... as you seem to have your solution I didn't investigate any further.