Hi Chris,
----- Mensaje original ----
> De: Christopher Barker <chris.bar...@noaa.gov>
> Para: Mailing List for the wxPython Float Canvas. <floatcanvas@mithis.com>
> Enviado: miércoles, 18 de marzo, 2009 20:10:47
> Asunto: Re: [fc] FloatCanvas update issues
>
> Vitor Bosshard wrote:
> > I have some objects on the canvas that can be dragged with
> > the mouse. While dragging, each time OnMove (a method on my custom
> > GUIMode) is called, it recalculates the position of the object,
> > redraws it, and triggers a render request that is calculated on
> > another thread
>
> How do you calculate it on another thread? Are you making any calls to
> wx functions/methods (other than CallAfter or PostEvenet)? from the
> other thread
>
> In general, wx is not thread-safe, so that may be the source of your issue.
I learned that the painful way, but I have fixed my app since. Only PostEvent
is called from the render thread.
> > It looks like my custom notifications are being swallowed by
> > wx whenever floatcanvas is generating a large amount of updates.
> >
> > The hack I found to work around this is to make the OnMove method
> > immediately return if less than .1 secs have passed since the last
> > call to it. This is the shortest time interval that fixes the problem
> > reliably.
>
> There is similar code in the EVT_SIZE handler -- if it takes longer to
> re-draw than the time between EVT_SIZE events, the display would get
> pretty flashy and clunky. However, aside form being slow and looking
> ugly, I don't remember anything actually breaking.
>
> > I just thought I'd let you know about this, I'm interested to hear of
> > any better ways to handle this issue.
>
> If you are making any wx calls in another thread, then that needs to be
> refactored. Otherwise, calls to wx.app.Yield inteh right place might help.
Where would I need to insert the Yield() call? I tried this in the event
handler and it made no difference.
> Can you duplicate it in a small, self contained sample?
It's attached. I managed to keep it at ~100 lines.
Vitor
¡Sé el Bello 51 de People en Español! ¡Es tu oportunidad de Brillar! Sube
tus fotos ya. http://www.51bello.com/
import wx, sys, time, threading
from wx.lib.floatcanvas.FloatCanvas import FloatCanvas
from wx.lib.floatcanvas.GUIMode import GUIMove
myEVT_PRINT = wx.NewEventType()
EVT_PRINT = wx.PyEventBinder(myEVT_PRINT, 1)
class PrintEvent(wx.PyCommandEvent):
def __init__(self,message):
wx.PyCommandEvent.__init__(self, myEVT_PRINT, wx.ID_ANY)
self._message = message
def GetMessage(self):
return self._message
class Renderer:
def __init__(self,parent):
self.parent = parent
self.requests = []
self.counter = 0
self.running = True
threading.Thread(target=self.render).start()
def MakeRequest(self):
self.requests.append(None)
def render(self):
while self.running:
if self.requests:
request = self.requests.pop(0)
# Make the CPU work
for i in range(100000): pass
self.counter += 1
wx.PostEvent(self.parent.log,PrintEvent("%s\n"%self.counter))
else:
time.sleep(.01)
class MyTextCtrl(wx.TextCtrl):
def __init__(self,parent):
wx.TextCtrl.__init__(self,parent,-1,style = wx.TE_MULTILINE)
sys.stdout = self
self.Bind(EVT_PRINT, self.OnPrint)
def OnPrint(self,e):
self.AppendText(e.GetMessage())
class MyCanvas(FloatCanvas):
def __init__(self, parent):
self.parent = parent
FloatCanvas.__init__(self, parent, BackgroundColor="BLACK")
self.circles = []
self.GUIMode = GUICustom(self)
def UpdateCircles(self, coord):
self.RemoveObjects(self.circles)
self.circles = []
for i in range(25):
self.circles.append(self.AddCircle((coord[0]+i%5*5,coord[1]+i),
Diameter=10,LineColor="White"))
class GUICustom(GUIMove):
def OnLeftDown(self,e):
self.starttime = time.time()
def OnLeftUp(self,e):
return
def OnMove(self,e):
if e.LeftIsDown() and e.Dragging():
# Uncomment these lines to see the fix
## t = time.time()
## if t - self.starttime < .05:
## return
## self.starttime = t
self.Canvas.UpdateCircles(self.Canvas.PixelToWorld(e.GetPosition()))
self.Canvas.parent.renderer.MakeRequest()
self.Canvas.Draw()
class TestFrame(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,"Test App")
self.renderer = Renderer(self)
self.log = MyTextCtrl(self)
self.Canvas = MyCanvas(self)
sizer = wx.BoxSizer()
sizer.Add(self.Canvas,3,wx.EXPAND)
sizer.Add(self.log,1,wx.EXPAND)
self.SetSizer(sizer)
self.Bind(wx.EVT_CLOSE,self.OnExit)
self.Show(True)
def OnExit(self,e):
self.renderer.running = False
self.Destroy()
app = wx.App()
frame = TestFrame(None,wx.ID_ANY)
app.MainLoop()
_______________________________________________
FloatCanvas mailing list
FloatCanvas@mithis.com
http://mail.mithis.com/cgi-bin/mailman/listinfo/floatcanvas