Possible bug in wx.gizmos.TreeListCtrl

I think I've found a bug in wx.gizmos.TreeListCtrl, could someone
confirm it please, and perhaps give me advice on how to submit it
- as reading the wxwidgets bug tracker system, it doesn't seem
applicable to wxPython. Here's the detail:

The class wx.gizmos.TreeListCtrl shows duplicated items when a tree
element is collapsed if the collapse causes the tree position within
the panel to move.

This can be seen on the demo distributed with wxPython. I first
observed this on ubuntu with python2.5 wx.python2.8.7.1 and also
tried it on the latest Debian Lenny with python2.5 and a freshly
downloaded wxPython2.8.10.1 and its associated demo (from the
wxPython site).

I've included sample code below - derived from the demo code -
which shows a TreeListCtrl and can be used to demonstrate the bug
with the following steps:

1 Run the code provided, and a frame will appear showing a tree
  list control with fifteen items.

2 Resize the frame vertical height just to the point where it fits
  the TreeListCtrl without scrollbars appearing.

3 Expand item 0 - this shows five subitems, and the bottom of the
  tree is pushed out of view, causing the vertical scrollbar to appear.

4 Move the vertical scrollbar down as far as it will go - revealing
  the bottom of the tree, and hiding some of the top of the tree

5 Expand item 12 - this opens another five sub-items and again pushes
  the bottom of the tree out of view - the scrollbar changes accordingly.

6 Move the scrollbar down again, as far as it will go - again revealing
  the bottom of the tree.

7 Collapse item 12. This causes the tree to re-position and the bug
  appears - you will now notice duplicate items have appeared on the tree.

The sample code follows,

Regards

   Bernie

···

#---------------------------------------------------------------
import wx
import wx.gizmos

class TestFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Test Frame", size=(300, 400))
        panel = TestPanel(self)

class TestPanel(wx.Panel):
    def __init__(self, parent):

        wx.Panel.__init__(self, parent, -1)
        self.Bind(wx.EVT_SIZE, self.OnSize)

        self.tree = wx.gizmos.TreeListCtrl(self, -1)

        isz = (16,16)
        il = wx.ImageList(isz[0], isz[1])
        fldridx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER,
                                                      wx.ART_OTHER, isz))
        fldropenidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN,
                                                      wx.ART_OTHER, isz))
        fileidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE,
                                                      wx.ART_OTHER, isz))

        self.tree.SetImageList(il)
        self.il = il

        # create some columns
        self.tree.AddColumn("Main column")
        self.tree.AddColumn("Column 1")

        self.tree.SetMainColumn(0) # the one with the tree in it...
        self.tree.SetColumnWidth(0, 175)

        self.root = self.tree.AddRoot("The Root Item")
        self.tree.SetItemText(self.root, "col 1 root", 1)
        self.tree.SetItemImage(self.root, fldridx,
                               which = wx.TreeItemIcon_Normal)
        self.tree.SetItemImage(self.root, fldropenidx,
                               which = wx.TreeItemIcon_Expanded)

        for x in range(15):
            txt = "Item %d" % x
            child = self.tree.AppendItem(self.root, txt)
            self.tree.SetItemText(child, txt, 1)
            self.tree.SetItemImage(child, fldridx,
                                   which = wx.TreeItemIcon_Normal)
            self.tree.SetItemImage(child, fldropenidx,
                                   which = wx.TreeItemIcon_Expanded)

            for y in range(5):
                txt = "item %d-%s" % (x, chr(ord("a")+y))
                last = self.tree.AppendItem(child, txt)
                self.tree.SetItemText(last, txt, 1)

        self.tree.Expand(self.root)

    def OnSize(self, evt):
        self.tree.SetSize(self.GetSize())

if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = TestFrame()
    frame.Show(True)
    app.MainLoop()

# -------- sample code ends -------------------------------------------

Bernard Czenkusz wrote:

I think I've found a bug in wx.gizmos.TreeListCtrl, could someone
confirm it please, and perhaps give me advice on how to submit it
- as reading the wxwidgets bug tracker system, it doesn't seem
applicable to wxPython.

It mostly is. Just include the details you have in this message and select the wxPython component.

BTW, an easy workaround for the problem would be to catch the EVT_TREE_ITEM_COLLAPSED event and call the tlc's Refresh method from the handler.

···

--
Robin Dunn
Software Craftsman

Bernard Czenkusz wrote:

Thanks for the reply - I've submitted the bug.

Unfortunately the Refresh method you suggest does not seem to make any difference, which is a pity.

What if you delay the call to Refresh with wx.CallAfter?

···

--
Robin Dunn
Software Craftsman