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

Reply via email to