wxPython fast and slow

iu2 israelu at elbit.co.il
Sun Mar 8 20:35:20 CET 2009


On Mar 8, 1:42 pm, Carl Banks <pavlovevide... at gmail.com> wrote:
> On Mar 8, 1:52 am, iu2 <isra... at elbit.co.il> wrote:
>
>
>
> > On Mar 6, 6:52 pm, Mike Driscoll <kyoso... at gmail.com> wrote:
>
> > > ...
> > > Can you post a sample application so we can try to figure out what's
> > > wrong? You might also cross-post this to thewxPythonmailing list.
> > > They might know.
>
> > > Mike- Hide quoted text -
>
> > > - Show quoted text -
>
> > Hi, thanks for your reply
>
> > Here is a sample application:
>
> > ----------------------------------------------------------
>
> > import wx
> > import time
>
> > class My_frame(wx.Frame):
> >     def __init__(self):
> >         wx.Frame.__init__(self, None, -1, 'Moving panel')
> >         self.surface = p = wx.Panel(self, size=(300, 130))
> >         self.square = wx.Panel(p, -1, size=(100, 100), pos=(0, 30))
> >         self.square.Bind(wx.EVT_PAINT, self.on_paint_square)
>
> >         btn_move = wx.Button(p, -1, 'Move panel', pos=(0, 0))
> >         self.Bind(wx.EVT_BUTTON, self.move_panel, btn_move)
>
> >         self.Fit()
>
> >     def move_panel(self, evt):
> >         def gen():
> >             for x in range(200):
> >                 yield x
> >             for x in range(200, 0, -1):
> >                 yield x
> >         for x in gen():
> >             self.square.SetPosition((x, 30))
> >             time.sleep(0.005)
>
> >     def on_paint_square(self, evt):
> >         square = evt.GetEventObject()
> >         dc = wx.BufferedPaintDC(square)
> >         dc.Pen = wx.Pen('blakc', 2)
> >         dc.Brush = wx.Brush('light blue')
> >         dc.DrawRectangle(0, 0, *square.GetSize())
>
> > app = wx.PySimpleApp()
> > My_frame().Show()
> > app.MainLoop()
>
> > ----------------------------------------------------------
>
> > Press the button and the panel moves to the right and then back to the
> > left.
> > While PyScripter is running the panel moves at a certain speed. You
> > can run the application from the Windows explorer with the same speed.
> > You don't need to run it from PyScripter.
> > When PyScripter is closed, the application runs much less quickly.
> > I experienced this on two PC-s.
> > Maybe this behavior is not even related towxPythonbut to the sleep
> > command. I don't know...
>
> It's not a good idea to call time.sleep inside a loop inside an event
> handler, which is what you are doing here.
>
> wx has a mechanism to call some sort of callback at timed intervals.
> (I don't know what it is but I know it has one.)  Instead of animating
> the box move inside the button callback, have it request that a
> callback be called after x seconds pass, and draw a single frame
> inside that callback.  Then invoke it again until you're done drawing.
>
> Here's a rough idea of what that might look like:
>
> class My_frame(wx.Frame):
>
>     # ... among other things ...
>
>     def move_panel(self,evt):
>         self.square_pos = 0
>         wx.set_timed_callback_of_some_sort(
>             self.draw_frame,0.005)
>
>     def draw_frame(self):
>         self.square.SetPosition((self.square_pos, 30))
>         self.square_pos += 1
>         if self.square_pos < 200:
>             wx.set_timed_callback_of_some_sort(
>                self.draw_frame,0.005)
>
> As for why it works fine in PyScripter but not when started from
> Explorer, well, let's just say that when you abuse callbacks like you
> did, you shouldn't expect reasonable behavior.
>
> Carl Banks

Hi,

Here is the timer version. It works even more slowly, even with
PyScripter active:

--------------------------------------------------------------
import wx
import time

class My_frame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Moving panel')
        self.surface = p = wx.Panel(self, size=(300, 130))
        self.square = wx.Panel(p, -1, size=(100, 100), pos=(0, 30))
        self.square.Bind(wx.EVT_PAINT, self.on_paint_square)

        btn_move = wx.Button(p, -1, 'Move panel', pos=(0, 0))
        self.Bind(wx.EVT_BUTTON, self.move_panel, btn_move)

        self.Fit()

    def on_paint_square(self, evt):
        square = evt.GetEventObject()
        dc = wx.BufferedPaintDC(square)
        dc.Pen = wx.Pen('blakc', 2)
        dc.Brush = wx.Brush('light blue')
        dc.DrawRectangle(0, 0, *square.GetSize())

    def move_panel(self, evt):
        def gen():
            for x in range(200):
                yield x
            for x in range(200, 0, -1):
                yield x
        self.track = gen()
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_timer_square, self.timer)
        self.timer.Start(milliseconds=1)

    def on_timer_square(self, evt):
        try:
            x = self.track.next()
            self.square.SetPosition((x, 30))
        except StopIteration:
            self.timer.Stop()

app = wx.PySimpleApp()
My_frame().Show()
app.MainLoop()
-----------------------------------------------------------------

I actually tried this one first. Due to the slow speed I changed to
looping inside the event.
I don't understand why it takes so long to move that square with
wx.Timer set to 1 ms interval. Perhaps its minimum interval is
actually 10 ms (as in Windows) so 100 steps really take 1 second.
But in that case, I really want to move the square in a tight loop
inside the wx.EVT_BUTTON event.

So allow me to rephrase my question:
Is there a way to move that square quickly and smoothly? Should 400
one-pixel moves should take so long on a 2.8 GHz core duo?

There is certainly something wrong in the code I wrote which I need
your help to figure out.
Can it be related to recurring paint events? If so how should I change
the code?

Thanks



More information about the Python-list mailing list