[wxPython] Memory management of wxOGLConstraints

Dear all,

I have posted the following at the beginning of this month already. Since there were no replies, nobody seems to see a reason for this wxPython behavior.

I would like to know if the included script also fails on other installations of Python and wxPython. I am running Python 2.0 and wxPython 2.2.2 on a windows NT machine. Important information for me will be on the behavior of the script on a Python 2.0 and wxPython 2.2.5 installation on a NT box.

Thanks for your efforts.

Joerg

----- Begin Included Message -----

Dear all,

I wish to build an application which is able to change the type of a wxOGLConstraint during run time. Trying this I found the following problems. They are probably related to the memory management of wxPython and C objects.

I am running wxPython 2.2.2 and Python 2.0 on a Windows NT machine.

1. Problem

The following procedure fails:
a) assigning a new created wxOGLConstraint to a Python variable
b) adding the constraint to the composite shape
c) recalculating the shape now is OK, until
d) the Python variable goes out of scope
e) all methods trying to access the constraint for calculation fail with a
   Windows NT error message

2. Problem

To go around this problem I tried the following:
a) assigning a new created wxOGLConstraint to a Python variable which does not go
out of scope
b) adding the constraint to the composite shape
c) all recalculations are fine
d) removing the constraint with either DeleteConstraint or DeleteConstraintsInvolvingChild
e) creating a new wxOGLConstraint
f) trying to assign the new constraint to the variable from step a) results in a
Windows NT error message

I have added some example code to this mail. Maybe I am using some classes the wrong way. The example fails as soon as line 86 is executed.

Does anybody know about a solution other than creating a new Python variable which does not go out of scope each time I have to change a constraint?

I need a reference in Python to the constraint, because I also want to use the SetSpacing method.

Thanks for your comments.

Joerg

Example code:

from wxPython import wx
from wxPython import ogl

ogl.wxOGLInitialize()

class MySatteliteShape(ogl.wxRectangleShape):
    def __init__(self, canvas, parent):
        ogl.wxRectangleShape.__init__(self, 10, 10)
        self.constraint = None
        self.SetCanvas(canvas)
        self.SetFixedSize(wx.true, wx.true)
        parent.AddChild(self)
        self.Show(wx.true)
        
class MyCompositeShape(ogl.wxCompositeShape):
    def __init__(self, canvas):
        ogl.wxCompositeShape.__init__(self)
        self.SetCanvas(canvas)
        self.SetDraggable(wx.true)
        self.SetX(100)
        self.SetY(100)
        self.icon = ogl.wxRectangleShape(50, 50)
        self.icon.SetCanvas(canvas)
        self.icon.SetDraggable(wx.true)
        self.icon.SetFixedSize(wx.true, wx.true)
        self.icon.Show(wx.true)
        self.AddChild(self.icon)
        self.Recompute()
        self.CalculateSize()
        self.Show(wx.true)
        
class MyCanvas(ogl.wxShapeCanvas):
    def __init__(self, parent):
        print 'Initializing base class canvas'
        ogl.wxShapeCanvas.__init__(self, parent)
        print 'Setting scrollbars'
        self.SetScrollbars(2, 2, 150, 150)
        print 'Setting background colour'
        self.SetBackgroundColour(wx.wxWHITE)
        print 'Creating diagram'
        self.diagram = ogl.wxDiagram()
        print 'Setting diagram in canvas'
        self.SetDiagram(self.diagram)
        print 'Setting canvas in diagram'
        self.diagram.SetCanvas(self)
        print 'Creating composite shape'
        self.shape = MyCompositeShape(self)
        print 'Adding shape to diagram'
        self.diagram.AddShape(self.shape)
        print 'Redrawing'
        dc = wx.wxClientDC(self)
        self.PrepareDC(dc)
        self.shape.Move(dc, 100, 100)
        self.diagram.Clear(dc)
        self.diagram.Redraw(dc)
        print 'Creating sattelite shape'
        self.sattelite = MySatteliteShape(self, self.shape)
        print 'Creating constraint'
        self.sattelite.constraint = ogl.wxOGLConstraint(ogl.gyCONSTRAINT_ABOVE, self.shape.icon, [self.sattelite])
        print 'Adding constraint'
        self.shape.AddConstraint(self.sattelite.constraint)
        print 'Recomputing composite constraints'
        self.shape.Recompute()
        print 'Finished MyCanvas.__init__'
        
    def OnLeftClick(self, x, y, keys=0):
        print 'Redrawing'
        dc = wx.wxClientDC(self)
        self.PrepareDC(dc)
        print 'Recomputing composite constraints'
        self.shape.Recompute()
        self.diagram.Clear(dc)
        self.diagram.Redraw(dc)
        print 'Finishe on left click'
        
    def OnRightClick(self, x, y, keys=0):
        print 'Deleting constraints'
        self.shape.DeleteConstraintsInvolvingChild(self.sattelite)
        print 'Creating new constraint'
        constraint = ogl.wxOGLConstraint(ogl.gyCONSTRAINT_BELOW, self.shape.icon, [self.sattelite])
        print 'Adding new constraint'
        self.shape.AddConstraint(constraint)
        print 'Recomputing composite constraints'
        self.shape.Recompute()
        print 'Storing new constraint'
        self.sattelite.constraint = constraint
        print 'Finished on right click'
        
class MyFrame(wx.wxFrame):
    def __init__(self):
        print 'Initializing base class frame'
        wx.wxFrame.__init__(self, None, -1, 'Test of wxOGLConstraints')
        print 'Creating canvas'
        self.canvas = MyCanvas(self)
        print 'Finished MyFrame.__init__'
        
    def OnCloseWindow(self, event):
        self.Destroy()

class MyApp(wx.wxApp):
    def OnInit(self):
        frame = MyFrame()
        frame.Show(wx.true)
        self.SetTopWindow(frame)
        print 'Finished MyApp.OnInit'
        return wx.true
        
app = MyApp(0)
app.MainLoop()
        
----- End Included Message -----

···

_______________________________________________
wxPython-users mailing list
wxPython-users@lists.sourceforge.net
http://lists.sourceforge.net/lists/listinfo/wxpython-users

I have posted the following at the beginning of this month already. Since

there were no replies, nobody seems to see a reason for this wxPython
behavior.

SOrry, it got lost in a bunch of other messages.

I would like to know if the included script also fails on other

installations of Python and wxPython. I am running Python 2.0 and wxPython
2.2.2 on a windows NT machine. Important information for me will be on the
behavior of the script on a Python 2.0 and wxPython 2.2.5 installation on a
NT box.

Yes it fails for me too.

I've done a fix and checked it in to CVS (main branch). Unfortunatly the
only workaround I can think of is to make sure that the python constraint
object is never deleted.

···

--
Robin Dunn
Software Craftsman
robin@AllDunn.com Java give you jitters?
http://wxPython.org Relax with wxPython!

_______________________________________________
wxPython-users mailing list
wxPython-users@lists.sourceforge.net
http://lists.sourceforge.net/lists/listinfo/wxpython-users

Hi again. I've been trying to get the column sorting thing working with a ListCtrl.
I've basically set up my app (a contact manager) to work similarly to the ListCtrl in the demo, BUT, instead of using numbers as keys to access the dictionary items, I'm using names (it's an address book afterall). I'm also keeping a separate namelist for sorting and display purposes.

So far, I am *totally* unable to figure a way around needing to use numbers as keys in order to get the column clicking feature to work properly. This means that I am going to have to do a massive revision of the entire program to have this feature.

What I want to do is quite simple: have the names sorted alphabetically upon opening (column 0), and have the option of sorting by email, etc. via column clicking.

Any suggestions or potential workarounds would be greatly appreciated - I'm going to start the redesign today- will post demo code, etc. if I figure out an elegant solution that may be useful to others.

thanks.

···

_______________________________________________
wxPython-users mailing list
wxPython-users@lists.sourceforge.net
http://lists.sourceforge.net/lists/listinfo/wxpython-users

So far, I am *totally* unable to figure a way around needing to use
numbers as keys in order to get the column clicking feature to work
properly. This means that I am going to have to do a massive revision
of the entire program to have this feature.

Well since the compare function gets the data values list of the items to be
compared, and since the data values can only be numbers, there has to be
some way to map from the number to the values. I don't think there is any
other way around it without doing a redesign of the wxListCtrl class.
(Which would be nice to dso for other reasons as well, but would be very
time consuming.)

What I want to do is quite simple: have the names sorted alphabetically

upon opening (column 0), and have the option of sorting by email, etc. via
column clicking.

Any suggestions or potential workarounds would be greatly appreciated -

Perhaps you could have two dictionaries, your current one and another to map
the integer list data values to the keys of your current dictionary. Then
just do a double lookup to get the value to compare.

BTW, it probably won't help your specific problem without some work but
something like the following will probably show up in the next release
somewhere in wxPython.lib. It is a mix-in class that can be combined with
some other class that either is a listctrl or has one.

class wxColumnSorterMixin:
    """
    A mixin class that handles sorting of a wxListCtrl in REPORT mode when
    the column header is clicked on.

    There are a few requirments needed in order for this to work genericly:

      1. The combined class must have a GetListCtrl method that
         returns the wxListCtrl to be sorted, and the list control
         must exist at the time the wxColumnSorterMixin.__init__
         method is called because it uses GetListCtrl.

      2. Items in the list control must have a unique data value set
         with list.SetItemData.

      3. The combined class must have an attribute named itemDataMap
         that is a dictionary mapping the data values to a sequence of
         objects representing the values in each column. These values
         are compared in the column sorter to determine sort order.

    """
    def __init__(self, numColumns):
        self._colSortFlag = [0] * numColumns
        self._col = 0
        self._colSortFlag[self._col] = 1

        list = self.GetListCtrl()
        if not list:
            raise ValueError, "No wxListCtrl available"
        EVT_LIST_COL_CLICK(list, list.GetId(), self.OnColClick)

    def SortListItems(self, col=-1, ascending=1):
        """Sort the list on demand. Can also be used to set the sort column
and order."""
        if col != -1:
            self._col = col
            self._colSortFlag[col] = ascending
        self.GetListCtrl().SortItems(self.ColumnSorter)

    def OnColClick(self, evt):
        self._col = col = evt.m_col
        self._colSortFlag[col] = not self._colSortFlag[col]
        self.GetListCtrl().SortItems(self.ColumnSorter)

    def ColumnSorter(self, key1, key2):
        col = self._col
        sortFlag = self._colSortFlag[col]
        item1 = self.itemDataMap[key1][col]
        item2 = self.itemDataMap[key2][col]
        if item1 == item2: return 0
        if sortFlag:
            if item1 < item2: return -1
            else: return 1
        else:
            if item1 > item2: return -1
            else: return 1

···

_______________________________________________
wxPython-users mailing list
wxPython-users@lists.sourceforge.net
http://lists.sourceforge.net/lists/listinfo/wxpython-users

I recently wrote a subclass of the wxListCtrl to do
          exactly this thing. The mixin idea is very cool!

          Just wanted to point out that while writing this subclass,
          I discovered that you don't really need to record the sort order
          for each column (_colSortFlag above). At any point in time,
          the list is sorted by one column in ascending or descending
          order, so you only need to record this. If the user clicks
          on the same column, flip the order. If the user clicks
          on some order, initialize that to ascending order.

          Recording sort orders for all columns seems to make sense only
          if you are sorting using MULTIPLE columns ...

          Y.

···

On Wednesday, February 28, 2001 at 2:41:40 PM, Robin Dunn wrote:

What I want to do is quite simple: have the names sorted alphabetically

upon opening (column 0), and have the option of sorting by email, etc. via
column clicking.

BTW, it probably won't help your specific problem without some work but
something like the following will probably show up in the next release
somewhere in wxPython.lib. It is a mix-in class that can be combined with
some other class that either is a listctrl or has one.

class wxColumnSorterMixin:
    """
    A mixin class that handles sorting of a wxListCtrl in REPORT mode when
    the column header is clicked on.

    There are a few requirments needed in order for this to work genericly:

      1. The combined class must have a GetListCtrl method that
         returns the wxListCtrl to be sorted, and the list control
         must exist at the time the wxColumnSorterMixin.__init__
         method is called because it uses GetListCtrl.

      2. Items in the list control must have a unique data value set
         with list.SetItemData.

      3. The combined class must have an attribute named itemDataMap
         that is a dictionary mapping the data values to a sequence of
         objects representing the values in each column. These values
         are compared in the column sorter to determine sort order.

    """
    def __init__(self, numColumns):
        self._colSortFlag = [0] * numColumns
        self._col = 0
        self._colSortFlag[self._col] = 1

_______________________________________________
wxPython-users mailing list
wxPython-users@lists.sourceforge.net
http://lists.sourceforge.net/lists/listinfo/wxpython-users