I'm currently developing and testing on Python 2.2, wxPython 2.2, Windows
ME.
My application is leaking resources despite taking every precaution I'm
aware of. Unfortunately, my problem is intermittent, and I have not been
able to duplicate the problem in a small sample app.
The troublesome window contains animation, and a paint happens 20 times per
second. I've left it running overnight with no problems. But once in a
while (and only when I'm doing stuff) the GDI resources dry up (the
resources are freed when I close my app).
Perhaps it has something to do with drawing lines after calling
SetClippingRegion. It doesn't seem to happen if I remove the
SetClippingRegion() or if I remove the DrawLine(). However, I can't seem to
reproduce the problem in a simple demo app. I tried various different
experiments like this, but the results seemed inconsistent, so I labeled the
problem "mostly intermittent sort of".
This made me ask: Is wxPaintDC.__del__() responsible for any necessary
resource cleanup? If so, is it possible that the destructor is being
deferred slightly by the python garbage collector (since python doesn't
promise to delete the dc immediately after it gets dereferenced)?
I tried a nasty little experiment to test this theory: In a small test app,
I stored an extra reference to the paint dc, and then dereferenced it later
in an OnTimer message (thereby simulating delayed destruction of the paint
dc). The test app ran fine until I threw extra paints at it by resizing to
app. It didn't bleed resources in this case, but it did crash after a
while.
def OnPaint(self, e):
dc = wxPaintDC(self)
self.grabby_paint_dc = dc # keep a nasty extra dc reference
... do some painting
def OnTimer(self, e):
if self.grabby_paint_dc:
self.grabby_paint_dc = None # delayed removal of nasty extra dc
reference
else:
... do some motion
self.Refresh()
That was a kinda interesting result, so I added this hack:
def OnPaint(self, e):
...
dc.__del__()
dc.__del__ = do_nothing
def do_nothing():
pass
The test app worked fine with the hack, so I added it to my application.
The resource leakage seemed to go away! Unfortunately the leak came back
again after more testing (no changes to the code). So now I'm back to
square one.
BTW, what exactly does BeginDrawing and EndDrawing do?
Here's a chunk of my code:
def OnPaint(self, e):
dc = wxPaintDC(self)
dx, dy = self.vu_off.GetWidth(), self.vu_off.GetHeight()
ox, oy = self.origin
temp_dc = wxMemoryDC()
temp_dc.BeginDrawing()
temp_dc.SelectObject(self.vu_temp)
temp_dc.Blit(0,0, dx,dy, dc, 0,0, wxCOPY, 0)
if self.active:
if self.shattered:
temp_dc.DrawBitmap(self.vu_shattered, 0,0, 1)
else:
temp_dc.DrawBitmap(self.vu_on, 0,0, 1)
else:
temp_dc.DrawBitmap(self.vu_off, 0,0, 1)
temp_dc.SetClippingRegion(0,0,dx,49)
for n in self.needles:
x,y = n.endpoint()
temp_dc.SetPen(n.pen)
temp_dc.DrawLine(ox, oy, ox+x, oy-y)
temp_dc.DestroyClippingRegion()
if self.overload:
temp_dc.DrawBitmap(self.vu_overload, 0,0, 1)
else:
temp_dc.DrawBitmap(self.vu_plate, 0,0, 1)
temp_dc.EndDrawing ()
dc.Blit(0,0, dx,dy, temp_dc, 0,0, wxCOPY, 0)