[wxPython] wxogl: memory leak on shape.SetClientData()

Hi,

When you do shape.SetClientData() [any data (int,
another object, etc)] memory leaks occur.
How can i overcome this?
In the demo code if u make a call to SetClientData()
then wxobjects leak corresponding to the shape
objects.
I have attached the sample code (ogl_shape.py)and the
memory leak output.
I'm running the program on Windows 2000

Also,
Is there any way I can handle doubleClicks on the
shape. At the moment I handle the
EVT_LEFT_DCLICK(self, self.onLeftDblClick) of the
wxShapeCanvas class

11:31:24: There were memory leaks.
11:31:24: ----- Memory dump -----
11:31:24: wxObject at $FE6BE8, size 12
11:31:24: wxObject at $FE7068, size 12
11:31:24: wxObject at $FE75B8, size 12
11:31:24: wxObject at $FE7AD0, size 12
11:31:24:
11:31:24:
11:31:24: ----- Memory statistics -----
11:31:24: 4 objects of class wxObject, total size 48
11:31:24:
11:31:24: Number of object items: 4
11:31:24: Number of non-object items: 0
11:31:24: Total allocated size: 48
11:31:24:
11:31:24:

from wxPython.wx import *
from wxPython.ogl import *
import string, sys

···

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

class MyFrame(wxFrame):
    def __init__(self, parent, ID, title,
pos=wxDefaultPosition,
                 size=wxDefaultSize,
style=wxDEFAULT_FRAME_STYLE):
        wxFrame.__init__(self, parent, ID, title, pos,
size, style)

# EVT_BUTTON(self, 1003, self.OnCloseMe)
# EVT_CLOSE(self, self.OnCloseWindow)

        self.CreateStatusBar(1, wxST_SIZEGRIP)
        splitter = wxSplitterWindow(self, -1,
style=wxNO_3D|wxSP_3D)
        log = ""

        tID = wxNewId()
        self.treeMap = {}
        self.moduleView = ModuleView(splitter, log,
self)
        self.moduleTree = wxTreeCtrl(splitter, tID,
                               style=wxTR_HAS_BUTTONS

                               wxTR_EDIT_LABELS |
                              
wxTR_HAS_VARIABLE_ROW_HEIGHT |
                               wxSUNKEN_BORDER)
        root = self.moduleTree.AddRoot("Configure
Modules")
        child = self.moduleTree.AppendItem(root, "A1")
        child = self.moduleTree.AppendItem(root, "B1")
        child = self.moduleTree.AppendItem(root, "C1")
        child = self.moduleTree.AppendItem(root, "D1")
        child = self.moduleTree.AppendItem(root, "E1")
  
        self.moduleTree.Expand(root)

        EVT_CLOSE (self, self.OnCloseWindow)

        splitter.SplitVertically(self.moduleTree,
self.moduleView)
        splitter.SetSashPosition(180, true)
        splitter.SetMinimumPaneSize(20)

    def OnCloseWindow(self, event):
        print "closing.."
        self.moduleView = None
        self.Destroy()
        print "OnCloseWindow()"
        
    def __del__(self):
        print "here"
# self.moduleView.__del__()

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

#class moduleTree(wxTreeCtrl):

#----------------------------------------------------------------------
# This creates some pens and brushes that the OGL
library uses.

wxOGLInitialize()

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

class DiamondShape(wxPolygonShape):
    def __init__(self, w=0.0, h=0.0):
        wxPolygonShape.__init__(self)
        if w == 0.0:
            w = 60.0
        if h == 0.0:
            h = 60.0

        ## Either wxRealPoints or 2-tuples of floats
works.

        #points = [ wxRealPoint(0.0, -h/2.0),
        # wxRealPoint(w/2.0, 0.0),
        # wxRealPoint(0.0, h/2.0),
        # wxRealPoint(-w/2.0, 0.0),
        # ]
        points = [ (0.0, -h/2.0),
                   (w/2.0, 0.0),
                   (0.0, h/2.0),
                   (-w/2.0, 0.0),
                   ]

        self.Create(points)

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

class RoundedRectangleShape(wxRectangleShape):
    def __init__(self, w=0.0, h=0.0):
        wxRectangleShape.__init__(self, w, h)
        self.SetCornerRadius(-0.3)

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

class MyEvtHandler(wxShapeEvtHandler):
    def __init__(self, log, frame):
        wxShapeEvtHandler.__init__(self)
        self.log = log
        self.statbarFrame = frame

    def UpdateStatusBar(self, shape):
        x,y = shape.GetX(), shape.GetY()
        width, height = shape.GetBoundingBoxMax()
        self.statbarFrame.SetStatusText("Pos: (%d,%d)
Size: (%d, %d)"
%
                                        (x, y, width,
height))

    def OnLeftClick(self, x, y, keys = 0, attachment =
0):
        shape = self.GetShape()
        canvas = shape.GetCanvas()
        dc = wxClientDC(canvas)
        canvas.PrepareDC(dc)

        if shape.Selected():
            shape.Select(false, dc)
            canvas.Redraw(dc)
            print "clicked"
            print shape.GetFunctor()
            print shape.getID()
        else:
            redraw = false
            shapeList =
canvas.GetDiagram().GetShapeList()
            toUnselect =
            for s in shapeList:
                if s.Selected():
                    # If we unselect it now then some
of the objects in
                    # shapeList will become invalid
(the control points
are
                    # shapes too!) and bad things will
happen...
                    toUnselect.append(s)

            shape.Select(true, dc)

            if toUnselect:
                for s in toUnselect:
                    s.Select(false, dc)
                canvas.Redraw(dc)

        self.UpdateStatusBar(shape)

    def OnEndDragLeft(self, x, y, keys = 0, attachment
= 0):
        shape = self.GetShape()
        self.base_OnEndDragLeft(x, y, keys,
attachment)
        if not shape.Selected():
            self.OnLeftClick(x, y, keys, attachment)
        self.UpdateStatusBar(shape)

    def OnSize(self, x, y):
        self.base_OnSize(x, y)
        self.UpdateStatusBar(self.GetShape())

# def OnMovePost(self, dc, x, y, oldX, oldY,
display):
# self.base_OnMovePost(dc, x, y, oldX, oldY,
display)
# self.UpdateStatusBar(self.GetShape())

    def OnRightClick(self, *dontcare):
        self.log.WriteText("%s\n" % self.GetShape())

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

class ModuleView(wxShapeCanvas):
    def __init__(self, parent, log, frame):
        wxShapeCanvas.__init__(self, parent)

        maxWidth = 1000
        maxHeight = 1000
        self.SetScrollbars(20, 20, maxWidth/20,
maxHeight/20)

        self.log = log
        self.frame = frame
        self.SetBackgroundColour(wxWHITE)
        self.diagram = wxDiagram()
        self.SetDiagram(self.diagram)
        self.diagram.SetCanvas(self)
        self.shapes =
        self.save_gdi =

        rRectBrush = wxBrush(wxNamedColour("MEDIUM
TURQUOISE"),
wxSOLID)

        self.MyAddShape(RoundedRectangleShape(95,70),
140, 255,
wxPen(wxRED, 1), rRectBrush, "A1")
        self.MyAddShape(RoundedRectangleShape(95,70),
345, 235,
wxPen(wxRED, 1), rRectBrush, "B1")
        self.MyAddShape(RoundedRectangleShape(95,70),
305, 60,
wxPen(wxRED, 1), rRectBrush, "C1")
        self.MyAddShape(RoundedRectangleShape(95,70),
100, 100,
wxPen(wxRED, 1), rRectBrush, "D1")

        dc = wxClientDC(self)
        self.PrepareDC(dc)
        for x in range(len(self.shapes)):
            fromShape = self.shapes
            if x+1 == len(self.shapes):
                continue
# toShape = self.shapes[0]
            else:
                toShape = self.shapes[x+1]
            line = wxLineShape()
            line.SetCanvas(self)
            line.SetPen(wxBLACK_PEN)
            line.SetBrush(wxBLACK_BRUSH)
# line.AddArrow(ARROW_ARROW)
            line.MakeLineControlPoints(2)
            fromShape.AddLine(line, toShape)
            self.diagram.AddShape(line)
            line.Show(true)

            # for some reason, the shapes have to be
moved for the line
to show up...
            fromShape.Move(dc, fromShape.GetX(),
fromShape.GetY())

            # line event handler
            evthandler = MyEvtHandler(self.log,
self.frame)
            evthandler.SetShape(line)
           
evthandler.SetPreviousHandler(line.GetEventHandler())
            line.SetEventHandler(evthandler)

    def MyAddShape(self, shape, x, y, pen, brush,
text):
        shape.SetDraggable(true, true)
        shape.SetCanvas(self)
        shape.SetX(x)
        shape.SetY(y)

############### Leaky Code Here
########################
        # leaks with SetClientData()
        #shape.SetClientData([[0,1], [2,4],
SomeObj()])
        #shape.SetClientData([[0,1], [2,4], 2])
        shape.SetClientData(2)
        #shape.SetClientData(3)
        #shape.SetClientData(1)
################ end leaky code
########################
        
        if pen: shape.SetPen(pen)
        if brush: shape.SetBrush(brush)
        if text: shape.AddText(text)
        #shape.SetShadowMode(SHADOW_RIGHT)
        self.diagram.AddShape(shape)
        shape.Show(true)

        evthandler = MyEvtHandler(self.log,
self.frame)
        evthandler.SetShape(shape)
       
evthandler.SetPreviousHandler(shape.GetEventHandler())
        shape.SetEventHandler(evthandler)

        self.shapes.append(shape)

    def __del__(self):
        for shape in self.diagram.GetShapeList():
            if shape.GetParent() == None:
                shape.SetCanvas(None)
                shape.Destroy()
        self.diagram.Destroy()
        wxOGLCleanUp()
        print "destroying..."

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

class SomeObj:
    def __init__(self):
        pass

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

class __Cleanup:
    cleanup = wxOGLCleanUp
    def __del__(self):
        self.cleanup()
        print "in __Cleanup"

# when this module gets cleaned up then wxOGLCleanUp()
will get called
#__cu = __Cleanup()
#---------------------------------------------------------------------------

class MyApp(wxApp):
    def OnInit(self):
        return true

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

def runTest():
    win = MyFrame(None, -1, "Module View", size=(650,
500),
                  style = wxDEFAULT_FRAME_STYLE)# |
wxFRAME_TOOL_WINDOW )
    win.Show(1)
            
#---------------------------------------------------------------------------

def main():
    app = MyApp(0)
    runTest()
    app.MainLoop()
# __cu = __Cleanup()
    
#---------------------------------------------------------------------------
   
main()

=====

__________________________________________________
Do You Yahoo!?
Yahoo! Movies - coverage of the 74th Academy Awards�

When you do shape.SetClientData() [any data (int,
another object, etc)] memory leaks occur.
How can i overcome this?

The client data in the C++ class is now used for OOR, so when you set it
again it is loosing the reference to the OOR data... On the other hand,
since OOR is available for wxShapes you should get the original object back
all the time so you should be able to just set your data as an attribute of
the shape object.

···

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

> When you do shape.SetClientData() [any data (int,
> another object, etc)] memory leaks occur.
> How can i overcome this?

The client data in the C++ class is now used for OOR, so when you set it
again it is loosing the reference to the OOR data... On the other hand,
since OOR is available for wxShapes you should get the original object

back

all the time so you should be able to just set your data as an attribute

of

the shape object.

I went to implement a fix for this and found that it is already there and
appears to be since 2.3.2. Which version are you using?

···

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