Why can’t I use the same tree item multiple times?


It's the continuing balance between ease-of-use and generality.

At a literal level, you can't use the same tree items in multiple places in the tree, because then various properties would become ambiguous, properties like TVGN_PARENT or TVIS_EXPANDED. (If a tree could be in two places, then it would have two parents, for example.)

Of course, this problem could have been solved by separating the item content from the item presence. So instead of just having an HTREEITEM, there would be, say, HTREENODE and HTREENODECONTENTS. The node would represent a physical location in the tree, and the item contents would represent the contents of that node: its name, icon, etc.

Sure, that could have been done, but remember the balance. You're making the common case hard in order to benefit the rare case. Now everybody who is manipulating treeviews has to worry about twice as many objects (what used to be one item is now a node plus contents). This is generally not the balance you want to strike when designing an interface.

When you design an interface, you want to make the common case easier than the rare case.

A program that wants this separation can, of course, do the separation manually. Put all the contents in a separate shareable structure and have your HTREEITEMs refer to that shared structure in their lParams. This is more work for the program, but now the cost is being shouldered by the one who wants the extra functionality.

Comments (17)
  1. Cooney says:

    Of course, this problem could have been solved by separating the item content from the item presence. So instead of just having an HTREEITEM, there would be, say, HTREENODE and HTREENODECONTENTS. The node would represent a physical location in the tree, and the item contents would represent the contents of that node: its name, icon, etc.

    This appeals to me logically – it’s analogous to model-view separation. Of course, we can simplify the common case by creating a wrapper API that generates HTREEITEMs by manipulating the node and nodecontents individually. You can then choose your level of abstraction.

    Your solution is fairly similar to mine, with the difference that it will be implemented slightly differently by everyone that does it. You could possibly fix that by writing a BSD-licensed wrapper and maintaining it as part of the normal dev kit.

  2. Jack Mathews says:

    Other than the lack of multiselect, I have to say the tree control is one of the most straightforward of the common controls.

  3. Chetan says:

    I’ve never done anything serious in windows GUI programming, but is this related?

    http://jhurani.blogspot.com/2004_01_01_jhurani_archive.html#107427087477478848

    Yesterday I just discovered something. Do not name a folder on your Windows Desktop as "desktop". Why?

    Because it leads to some crazy behavior in a special case. Here are the steps. It happens on Windows 2000 Professional and Server, and Windows XP Home/Professional at least.

    – Open explorer in the folders view. (Press the Win-E combo.)

    – Right click in the list pane and create a new folder. Rename

    it to "desktop".

    – Right click in the list pane and create another new folder.

    – "Go in" the last created folder.

    – Create another new folder or a new file here using the same old

    context menu.

    – Press F5 (once or twice).

    In the Folder tree view on left you’ll see empty entries. The only use of this explorer window now is to create more such empty entries using refresh-view (F5). Clicking on "C:" for example leads you to no where. Try it.

    The special case is not very special. Later whenever you create a new file/directory and refresh, you’ll see it.

    Sometimes a dialog pops up saying "c:…..New Folder" etc.. refers to a location that is not available.

  4. Parts of TreeView make the common case hard to benefit the rare case though – which is kind of odd.

    Namely, there are two images for each TreeView item – one for when the item is selected, and one for when it’s not.

    I’ve never seen this used by anyone.

    However, the common case used throughout the OS and apps is that you want a different image when the node is opened than when it’s closed.

    It’s a really strange design choice to have it the way it’s actually implemented.

    Of course, these days you’d probably want all the permutations of open/closed/selected/unselected/hot/cold…

  5. Chetan:

    It’s not related. The special name "desktop" (lousy choice – should have been a GUID for the filename) is used by the shell, that’s all.

  6. Johan Creuk says:

    Simon,

    Think of the case when a tree view is driving a more detailed view pane, also on-screen. In this case, it makes sense for the selection to change the icon. For example, if the "folder" in the tree view is on display in the list pane, as in Explorer, it makes sense for that folder to appear "open".

    On the other hand, I’d expect the open/close status of a tree view to be indicated by the expand/collapse widget showing either + or -, and also by the fact that there are items displayed beneath a given item!

    I’d say a different icon for selected is the more useful case.

  7. Orion Adrian says:

    Wouldn’t it have been possible to add an additional struct containing the content information and an additional method that would allow you to populate the node with the struct so that the creation of nodes would be simpler. I.e. you could have gone with both approaches.

    Orion Adrian

  8. Centaur says:

    Once you allow a tree node to be in several different places of the tree, it is no longer a tree. Now try to explain Joe Random User what a DAG is and why it works :)

  9. Johan: Never mind – I had a brain fart and confused the two models.

    I was under the impression that Explorer used the common-case I was describing – it doesn’t.

  10. Andrew says:

    When you design an interface, you want to make the common case easier than the rare case.

    Damn right. I can’t remember the number of arguments I’ve had with people who want to design for the cool but esoteric case. It’s kind of like the premature generalization that people seem to be prone to when designing inheritance hierarchies.

  11. For comparison, GtkTreeView is a concrete example

    that uses the Model/View/Controller approach.

    http://liw.iki.fi/liw/texts/gtktreeview-tutorial.html

  12. Jon Potter says:

    I’d like to know why many treeview (and listview) notification messages send a structure that contains fields that aren’t properly filled in. Eg the lParam field isn’t supplied, or coordinates aren’t correct for custom draw. Things like that.

    Any reasonably complicated program is surely going to use the lParam field for its own data – wouldn’t the "common case" justify providing this rather than necessitating an additional call to TVM_GETITEM, etc?

  13. Merle says:

    "When you design an interface, you want to make the common case easier than the rare case."

    Hear, hear.

    And I don’t think it’s analogous to model-view. Your model is probably not stored in the tree item — the item is more a placeholder for content, much as buttons or menu labels are. You wouldn’t *really* put your controller code directly in btn1_onClick, would you? Nor would you store information in the button object itself.

    I think of tree items as containing references to data (or actions).

  14. Chetan: You don’t say *where* you’re creating these folders.

    A few weeks ago I uninstalled some app that actually deleted the physical Desktop folder under <root>:Documents And Settings<myid>. In the Win32 shell there are two concepts of a "desktop". This physical folder (which allows you to have a messy desktop with things in it) and the shell namespace root, which is not a real folder.

    If you delete the physical folder, every time you try to refresh the "screen desktop" you’ll get an error saying that the location refers to something that is unavailable. If you re-create the physical desktop folder then the problem goes away.

  15. Jon:

    Two things:

    Firstly, you need to check the flags to see which parts of the structure are valid; not all flags are set for each notification message.

    Secondly, the reason for not using lparam for this is because… well… what do you do if you’re not in the same process as the treeview control? Your lParam data would be invalid.

  16. Raymond Chen says:

    Jon: I just spent fifteen minutes going through all the treeview notifications and all of the ones that refer to items do set the lParam (at least that’s what it looked like to me), so I’m not sure which notifications you’re talking about. If any fail to set it, it’s just an oversight.

    Simon: Yeah, the selected image thingie violates the principle of "simple is easy". Nobody’s perfect.

  17. Jon Potter says:

    LVN_DELETEITEM and LVN_GETDISPINFO are two examples where the listview doesn’t supply the lParam value and obviously should. The coordinates supplied for NM_CUSTOMDRAW are sometimes invalid under XP. Ok, these are probably just oversights but they’re annoying nonetheless :)

Comments are closed.

Skip to main content