I was using PseudoDC and moving objects around and kept
getting errors in rectangles calculation inside of methods. I built a
simpler app to reproduce the problem. In this app, there’s no
PseudoDC and I don’t draw the rectangle. I have only a text control
to display the rectangles coordinates. I create the rectangle in a
separate class, then translate it as if it had been dragged. I then take
the union of the original rectangle with the new rectangle, and inflate
this by 5. This gives me the area that would need to be refreshed (if I
was drawing to the canvas).
The problem is when the “translate” method
returns the inflated calculated refresh rectangle. If I assign the
inflated rectangle to a new variable, and return that, the calling statement
receives an error on the first coordinate. But if I take a copy of the rectangle
object and return that there is no error. Here is the code that works.
See below for an explanation of the weird behavior:
import wx
import copy
class frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,
None, title=“test move”,size=(400,400))
#text control is
used to capture a click, and display results
self.editTxt=wx.TextCtrl(self, wx.ID_ANY, “text”,pos=(0,0),
style=wx.TE_MULTILINE)
self.editTxt.Bind(wx.EVT_LEFT_DOWN, self.OnMouse)
#subObj is a
class holding a rectangle (wx.Rect) only for now
self.p=subObj(100,100,50,50)
def OnMouse(self,event):
rU=self.p.translate(5,10)
self.editTxt.Clear()
self.editTxt.WriteText("subObj rect= " + str(self.p.r) +
“\n” +
"calc rect = " +str(rU) + “\n”)
class subObj(object):
def __init__(self,x,y,width,height):
self.r =
wx.Rect(x,y,width,height)
def translate(self,dx,dy):
“”"
This simulate
dragging (without displaying it). It returns the area that would need
refreshing,
by taking the
union of the original and the displace rectangle"""
r0 =
copy.copy(self.r) #remember the original rectangle
self.r.OffsetXY(dx,dy) #move the class rectangle (by
x=5 and y=10)
r0.Union(self.r) #
union of two rectangle, r0 is modified
rUpdate=
r0.Inflate(5,5) # inflate the resulting rectangle by 5 all around,
r0 is modified
# at this point
rUpdate reads rect = (95,95, 65,70)
rUpdateC=copy.copy(rUpdate)
return rUpdateC
class App(wx.App):
def OnInit(self):
myFrame=frame()
myFrame.Show()
return True
if name == ‘main’:
app = App()
app.MainLoop()
**************EXPLANATION:
Look at the translate method is class subObj:
As written, it return a rectangle = (95,95,65.70) which is
correct.
If I leave the code as is (i.e I still take a copy of
rUpdate), but I return rUpdate instead of its copy(rUpdateC),
the code returns and error: rectangle = (0,95,65,70). The
first coordinates is wrong.
Wait it gets better:
If I comment out the copy statement, and return rUpdate, I
get rectangle = (30013472,95,65,70) – first coordinate is very wrong.
Finally, if I run this last version outside of the debugger
(I use Wing), I get a different large number for the first coordinate.
Can somebody explain to me what is happening? I
believe it has to do with passing a reference to an object that is modified inside
the method.
It is as if the object inside the method was starting to be
destroyed while the calling statement is trying to update its variable.
(in fact, I sometimes get a rectangle where all 4
coordinates are wrong).
At first I thought it was a peculiarity of Python. But
I build a separate test app without the wx.rect, where I create a simple
rectangle class from a list with four elements, and ran a similar test. I
had no problem passing a pointer to a list that was modified inside the class
method out to a calling statement.
Please help me understand this. I don’t mind returning
copies of objects modified in a method– I’d just like to know why I
have to do this.
Norm Frenette