Search code examples
delphitreeviewdelphi-7multi-select

Understanding how multiselection of TTreeView items in Delphi 7 works


Can some one explain me, how MultiSelectStyle, Selected and Selected.Count properties works for TTreeView in Delphi 7? I've been away Delphi coding for years and unless someone points me out, what do I miss, I see absolutely no logic behind that.

To the point. I have a routine that fills TTreeView with contents of selected folder. It uses recurence, so each folder is represented as node with children -- it's subfolders and files. User can select multi items on a tree, because MultiSelect is set to True. In MultiSelectStyle group I've set all four child properties to True as well (maybe that was a mistake).

As a debug of my program (which works exactly opposite, I would expect) I have this code:

ShowMessage(IntToStr(tvShell.Selected.Count) + ' selected');

for i := 0 to (tvShell.Selected.Count - 1) do
begin
    ShowMessage(tvShell.Selected.Item[i].Text);
end;

So I run my program and select any folder. Tree renders and I see:

  • root node with full path of selected folder as Text and with six children, as selected folder contains six subfolders and no files,
  • these six subfolders contains only files, so six children of root node contains respectful number of children, for example -- first contains 44 (files or items) and last contains 9 (items or files).

Using Ctrl and mouse, I select first (44 files) and last (9 files) tree node (children of root node) and hit the button that executes above mentioned debug code.

Example tree contents

What do I expect? I see two items selected. Since msVisibleOnly is set to True among MultiSelectStyle, I expect to have tvShell.Selected.Count set to 2 and see three messages.

What do I get? First message says that I have... nine items selected and when I continue, I'm getting additional nine messages, showing me contents of last folder (tree children). The funniest part is that among tvShell.Selected there are no sign of those two, that are actually selected by me! WTF?

Non-sense continues...

I repeat all these steps, but this time I'm selecting (clicking) on last folder (children) and with Ctrl button pressed, I'm clicking on first folder (root's children). As a human I again see, that I have two items selected. When looking at this tree I visually see no difference in selection. But Delphi does.

When executing debug code, this time I'm getting information that there are fourty four items selected and I'm getting 44 additional message boxes showing me contents of first folder. Completely confused, I'm clicking + next to first and last folder to see, if there are any items selected inside, but no (since msVisibleOnly is set to True).

I see, how does it work (always claiming that children of last time clicked item are all among selected items), but I don't understand it. Where is the logic behind this, if any? How this can be useful, if results from the code does not reflect the reality?

Sorry, for hard tongue, but this is complete stupidity for me. Since I don't code in Delphi (I actually hate that language for more things like that) I don't look for an enlightenment or explanation, why this works like it works (although, if someone have some spare time, I'll be more than happy to read it).

But I would truly be happy, if someone could explain me, what magic do I have to do in code and among TTreeView properties, to get from code, what is truly selected, not the Delphi's false interpretation of reality. If I see two items selected, I want tvShell.Selected.Count to be set to 2 and I want tvShell.Selected contain exactly two items -- both, that I have selected. Nothing more, nothing less.

Sorry, that this question is such long, but I had to react after frustration I've got, when finding (again, after years), that Delphi is really a weird language.


Solution

  • Your code displays the value of

    tvShell.Selected.Count
    

    That's the number of nodes that are direct children of tvShell.Selected. Remember that tvShell.Selected is just a single node.

    You probably meant to use

    tvShell.SelectionCount
    

    And you then display

    tvShell.Selected.Item[i].Text
    

    These are the captions of the direct children of tvShell.Selected.

    If you want to iterate through all selected nodes then you can do it like this:

    for i := 0 to tvShell.SelectionCount-1 do
      DoSomething(tvShell.Selections[i]);
    

    I recommend reading the online help when you are faced with situations like this. Particularly for Delphi 7 the documentation is very clear. For Selected the documentation states:

    Specifies the selected node in the tree view.

    property Selected: TTreeNode;

    Description

    Read Selected to access the selected node of the tree view. If there is no selected node, the value of Selected is nil.

    .....

    If the MultiSelect property is True and the MultiSelectStyle property includes msControlSelect, then Selected returns the last node clicked on, even if that click deselected the node. For a current selection status when MultiSelect is True, refer to the Selections property.

    And then when you follow on to the documentation for Count it says:

    Indicates the number of direct descendants of a tree node.

    property Count: Integer;

    Description

    Use Count to determine how many child nodes belong to a tree node. Count includes only immediate children, and not their descendants. Count can be useful when iterating through the children of a tree node.

    In other words, the documentation tells you just the same as I have told you.