[wxPython] Trouble with Python data attached to wxTreeCtrl

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

[wxPython] Trouble with Python data attached to wxTreeCtrl

Gary Herron-3

I've got a python program using pyWindows which crashes when run on NT.
(I don't yet know what happens on Unix or other window platforms.)  I've
also found a not-to-satisfactory work-around, but perhaps someone can
shed some light on this.

I am attaching a python item (an instance of a class of my invention) to
the items in a wxTreeCtrl using SetPyData, and retrieving it later with
GetPyData.  The program crashes (in a call to DeleteChildren)  when I
collapse an item, or when I attempt to quit (at which point
DeleteChildren or something similar is apparently called as part of the
cleanup).

If I carefully keep a global reference to all of my data items, all is
fine.  The error appears to occur when wxWindows follows a pointer to a
bogus (i.e., deleted) python item.  Is this a (known) bug or a feature,
and if it is a feature, is there a more elegant solution than just
keeping a global reference to every item I create?

I include a copy of the program for anyone who wishes to look at it.  It
is almost a direct copy of the pyWindows demo program pyTree.py.
Comment and uncomment line 13 to see failure or successful runs. The
hierarchical objects I am displaying are (for the moment) just files in
the local file system.

--
Dr. Gary Herron <[hidden email]>
206-287-5616
Alias | Wavefront
1218 3rd Ave, Suite 800, Seattle WA 98101
#!/usr/bin/env python

from wxPython import wx
import sys, os
from stat import *

GlobalObjList = []

class Obj:
        def __init__(self, obj):
                self.obj = obj
                # Uncomment next line to eliminate crash.
                # GlobalObjList.append(self)

        def Name(self):
                head, tail = os.path.split(self.obj)
                if tail:
                        return tail
                else:
                        return head
               
        def HasChildren(self):
                return os.path.isdir(self.obj)
       
        def Children(self):
                objList = os.listdir(self.obj)
                objList.sort()
                objList = map(lambda obj,parent=self.obj: os.path.join(parent,obj),
                                          objList)
                objectList = map(Obj, objList)
                return objectList
       
        def __str__(self):
                return self.obj
       
        def __repr__(self):
                return self.obj

        def __del__(self):
                print 'del', self.obj
               

#----------------------------------------------------------------------

class pyTree(wx.wxTreeCtrl):

        def __init__(self, parent, id, obj):
                wx.wxTreeCtrl.__init__(self, parent, id)
                self.root = self.AddRoot(obj.Name(), -1, -1, wx.wxTreeItemData(''))
                self.SetPyData(self.root, obj)
                if obj.HasChildren():
                        self.SetItemHasChildren(self.root, wx.TRUE)
                wx.EVT_TREE_ITEM_EXPANDING(self, self.GetId(), self.OnItemExpanding)
                wx.EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed)
                wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
                self.output = None

        def SetOutput(self, output):
                self.output = output

        def OnItemExpanding(self,event):
                item = event.GetItem()
                obj = self.GetPyData(item)
                children = obj.Children()
                for child in children:
                        new_item = self.AppendItem(item, child.Name(), -1, -1,
                                                                           wx.wxTreeItemData(''))
                        self.SetPyData(new_item, child)
                        if child.HasChildren():
                                self.SetItemHasChildren(new_item, wx.TRUE)

        def OnItemCollapsed(self, event):
                item = event.GetItem()
                self.DeleteChildren(item)

        def OnSelChanged(self, event):
                if not self.output:
                        return
                obj = self.GetPyData( event.GetItem() )
                apply(self.output, (`obj`,))



#----------------------------------------------------------------------
if __name__ == '__main__':

        class MyFrame(wx.wxFrame):

                def __init__(self):
                        wx.wxFrame.__init__(self, wx.NULL, -1, 'PyTreeItemData Test',
                          wx.wxDefaultPosition, wx.wxSize(600,500))
                        split = wx.wxSplitterWindow(self, -1)
                       
                        if sys.platform == 'win32':
                                tree = pyTree(split, -1, Obj('C:\\'))
                        else:
                                tree = pyTree(split, -1, Obj('/'))
                               
                        text = wx.wxTextCtrl(split, -1, '', wx.wxDefaultPosition,
                                                                 wx.wxDefaultSize, wx.wxTE_MULTILINE)
                        split.SplitVertically(tree, text, 200)
                        tree.SetOutput(text.SetValue)
                        tree.SelectItem(tree.root)

        class MyApp(wx.wxApp):
                 
                def OnInit(self):
                        frame = MyFrame()
                        frame.Show(wx.TRUE)
                        self.SetTopWindow(frame)
                        return wx.TRUE

        app = MyApp(0)
        app.MainLoop()


Reply | Threaded
Open this post in threaded view
|

Re: [wxPython] Trouble with Python data attached to wxTreeCtrl

Robin Dunn
> I've got a python program using pyWindows which crashes when run on NT.
> (I don't yet know what happens on Unix or other window platforms.)  I've
> also found a not-to-satisfactory work-around, but perhaps someone can
> shed some light on this.
>
> I am attaching a python item (an instance of a class of my invention) to
> the items in a wxTreeCtrl using SetPyData, and retrieving it later with
> GetPyData.  The program crashes (in a call to DeleteChildren)  when I
> collapse an item, or when I attempt to quit (at which point
> DeleteChildren or something similar is apparently called as part of the
> cleanup).
>
> If I carefully keep a global reference to all of my data items, all is
> fine.  The error appears to occur when wxWindows follows a pointer to a
> bogus (i.e., deleted) python item.  Is this a (known) bug or a feature,
> and if it is a feature, is there a more elegant solution than just
> keeping a global reference to every item I create?
>

Hmmm...  I thought it would be a simple reference counting problem, but your
sample doesn't crash for me (with my current working version.)  It sounds
like something that was fixed in 2.1b1 having to do with aquiring the
interpreter lock when Py_DECREF is called.  Are you using this version?  How
does it crash (GPF or other...) ?

--
Robin Dunn
Software Craftsman
[hidden email]
http://AllDunn.com/robin/
http://AllDunn.com/wxPython/  Check it out!



_______________________________________________
wxPython-users maillist  -  [hidden email]
http://starship.python.net/mailman/listinfo/wxpython-users




Reply | Threaded
Open this post in threaded view
|

Re: [wxPython] Trouble with Python data attached to wxTreeCtrl

Robin Dunn
>
> Hmmm...  I thought it would be a simple reference counting problem, but
your
> sample doesn't crash for me (with my current working version.)  It sounds
> like something that was fixed in 2.1b1 having to do with aquiring the
> interpreter lock when Py_DECREF is called.  Are you using this version?
How
> does it crash (GPF or other...) ?
>

To the group:  Gary was on an old version, and this was the old Py_DECREF in
threads bug...  No need to worry about it.

Robin


_______________________________________________
wxPython-users maillist  -  [hidden email]
http://starship.python.net/mailman/listinfo/wxpython-users