CustomTreeCtrl windows added via SetWindow aren't properly handled

Hello everyone,

I am using a CustomTreeCtrl, and I have noticed that if I use the SetWindow method of a GenericTreeItem, the window isn't hidden if any of the parents are collapsed. Is this a bug or do I just not understand why this might be expected?

I noticed in CustomTreeCtrl's DoAddItem there is this:

        if wnd is not None:
            self._hasWindows = True
            self._itemWithWindow.append(item)

Now, when an item is collapsed, HideWindows is called, which iterates over everything in self._itemWithWindow and hides the windows. However, when an the window is set via SetWindow on the GenericTreeItem, the GenericTreeItem instance never gets added to the _itemWithWindow list in the CustomTreeCtrl. This (I believe) causes it to not be hidden when any upper parent is collapsed. It doesn't appear that a GenericTreeItem has access directly to the CustomTreeCtrl to add itself to this list, so I am not sure what a solution would be. I figured if there was a SetItemWindow on the CustomTreeCtrl that could work just fine, but there only appears to be a GetItemWindow.

Any ideas on how to have windows added to items after creation behave properly? The easiest solution I see would be to create a SetItemWindow which calls the items SetWindow and then adds the window to the _itemWithWindow list, though it would be optimal if SetWindow could be used as well. Attached is a runnable demo of this issue.

Thanks again Andrea for the great control, by the way!

- Mike

ctwndnohide.py (679 Bytes)

Hi Mike,

Great! I noticed DeleteWindow on a GenericTreeItem also has the same
issue but in reverse. The item never gets /removed /from the tree's
_itemWithWindow, so later it will crash when you remove the item if you
had previously properly added the window (say via SetItemWindow, or
passed it in initially on item creation). From 'Delete' in
CustomTreeCtrl [~#3433]:

       # Remove the item with window
       if item in self._itemWithWindow:
           wnd = item.GetWindow()
           wnd.Hide()

If you previously used item.DeleteWindow, item.GetWindow will return
None, and you will get an exception on the next line that NoneType has
no attribute Hide. So I guess we also need a DeleteItemWindow in
CustomTreeCtrl which removes the item from _itemWithWindow.

Once those are there, SetWindow and DeleteWindow on a GenericTreeItem
should probably not be "public" anymore, right (have underscores
appended to the method names)?

Though it seems a shame to lose these methods on the items themselves.
One of the nicest things about going from a TreeCtrl to a CustomTreeCtrl
for me was being able to call so many methods right on the tree items
themselves. You can just pass them around as you please and perform many
useful operations without worrying about also having the tree object
available. Though, I don't see any particularly elegant way to
accomplish this. Oh well!

Yes, I do see the same problem, and at the moment I can't think about
a solution off the top of my head... but I will think about it.
However, if I had to choose, I would go with the implementation of
SetItemWindow and DeleteItemWindow on CustomTreeCtrl moving the
GenericTreeItem to "private" methods (I am shivering on thoughts about
C++ :smiley: ).

PS - Is the below method how you implemented SetItemWindow? It seems to
work well but I don't want to make any silly mistakes.

   def SetItemWindow(self, item, wnd):
       """Sets the window for the given item"""

       if wnd is not None:
           self._hasWindows = True
           if not item in self._itemWithWindow:
               self._itemWithWindow.append(item)

       item.SetWindow(wnd)

Almost perfect, except one thing: what happens if the item already
have a window? I would probably modify it to something like:

    def SetItemWindow(self, item, wnd):
        """Sets the window for the given item"""

        if wnd is not None:
            self._hasWindows = True
            if not item in self._itemWithWindow:
                self._itemWithWindow.append(item)
            else:
                oldWnd = item.GetWindow()
                oldWnd.Destroy()

        item.SetWindow(wnd)

More or less, it should be ok (not tested). I still have to send a
patch to Robin: the summer holidays left almost no one in the office
and I am struggling to keep the pace at work :smiley: :smiley:

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

···

On 7/17/07, Mike Rooney wrote: