help needed on wx.Timer event handling

hi,
I’m facing an issue when develope a mplayer front-end app use wxpython, in my application, I use a wx.Timer instance and bind a handler function with it to update the progress bar when playing a media, but I found the events occured are stored as a queue which means my other event handlers are blocked(actually delayed) since lots of timer event occured before the event which I’d like to be handled imediately. for instance, when I click on the pause button, its handler OnPause() which disable the pause button itself and pause the play should be executed immediately, but in practice, the pause behavor was always delayed to wait for several timer events to be processed.
I’m pretty new to wxpython, actually I’ve zero experience on gui programming, so just feel free to point out I’m walking on a stupid way, guide me to the right direction is much appreciated. here is some pieces of my fucking codes.

In MainWindow.py

self.Bind(wx.EVT_TIMER, self.OnTimerEvent, self.timer)
Publisher().subscribe(self.UpdateProgressBar, ‘Controler.ProgressBar.Update’)

def OnTimerEvent(self, event):
if MplayerState.state == MplayerState.PLAYING:
t = Thread(target=self.ctl.UpdateProgressBar)
t.setDaemon(True)
t.start()
#time.sleep(0)
else:
self.StopTimer()
debug(‘Timer Event: current player state - %s’ % MplayerState.states[MplayerState.state])
event.Skip()

def UpdateProgressBar(self, msg):
try:
self.lock.acquire()
if MplayerState.state == MplayerState.PLAYING:
percent = msg.data
debug(‘MainWindow: UpdateProgressBar - percent = %s’ % percent)
self.progress_bar.SetValue(percent)
self.lock.release()
if percent == 1000:
self.StopTimer()
return
else:
self.lock.release()

    except Exception, e:
        self.lock.release()
        self.StopTimer()
        debug('UpdateProgressBar: %s' % e.message)


in controler.py

def UpdateProgressBar(self):
try:
if MplayerState.state == MplayerState.PLAYING:
debug(’==== UpdateProgressBar ====’)
media_length = self.player_manager.mpGetMediaLength()
#debug(‘Media length: %s’ % media_length)
#time.sleep(0.2)
current_pos = self.player_manager.mpGetCurrentPos()
#debug(‘Current position: %s’ % current_pos)
if ( not media_length ) or ( not current_pos):
percent = 1000
#raise Exception(“Can not get play progress info.”)
else:
percent = int(float(’%.3f’ % ( current_pos / media_length )) * 1000)
#percent = self.player_manager.mpGetPercentPos()
debug(‘Percentage: %s’ % percent)
Publisher().sendMessage(‘Controler.ProgressBar.Update’, percent)
except Exception, e:
#Publisher().sendMessage(‘Controler.ProgressBar.Error’, ‘error’)
debug(’%s: UpdateProgressBar: %s’ % (self.getName(), e.message,))

Best Regards

jason zhang wrote:

hi,
I'm facing an issue when develope a mplayer front-end app use wxpython, in my application, I use a wx.Timer instance and bind a handler function with it to update the progress bar when playing a media, but I found the events occured are stored as a queue which means my other event handlers are blocked(actually delayed) since lots of timer event occured *before* the event which I'd like to be handled imediately. for instance, when I click on the pause button, its handler OnPause() which disable the pause button itself and pause the play should be executed immediately, but in practice, the pause behavor was always *delayed* to wait for several timer events to be processed.

IIRC, timer events are relatively low priority so if there are other events pending then the timer events may not be sent until they have been processed. This may be part of what you are seeing. Another part may be that if the ui thread gets blocked waiting for some function to return then there will be no events delivered at all until the (relatively) long running task completes.

It's not real clear from your code snippets but it looks like you may be breaking the thread rule. In a nutshell you should not invoke any function or method that accesses or manipulates a UI object from a thread that is not the UI thread. See LongRunningTasks - wxPyWiki and Non-Blocking Gui - wxPyWiki

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

IIRC, timer events are relatively low priority so if there are other events pending then the timer events may not be sent until they have been processed. This may be part of what you are seeing. Another part may be that if the ui thread gets blocked waiting for some function to return then there will be no events delivered at all until the (relatively) long running task completes.

It’s not real clear from your code snippets but it looks like you may be breaking the thread rule. In a nutshell you should not invoke any function or method that accesses or manipulates a UI object from a thread that is not the UI thread. See http://wiki.wxpython.org/LongRunningTasks and http://wiki.wxpython.org/Non-Blocking_Gui

Robin Dunn

Software Craftsman

http://wxPython.org Java give you jitters? Relax with wxPython!

Robin,
the issue I’m suffering is the timer event seems has higher priority that other event such as EVT_BUTTON, and my event handler to handle pause button clicked have to wait for several timer events processed and caused a unexpected delayed response to user, and I’m not breaking the thread rule actually, I do all ui refresh operations in gui main thread, below is the event handle procedure for a timer event.

···

On Thu, Nov 20, 2008 at 6:24 AM, Robin Dunn robin@alldunn.com wrote:

------MainWindow(gui)-------| |---------Controler---------|
> > >

----------------| | new worker thread | |---------------------| |
OnTimerEvent() |-----------------------------|->| UpdateProgressBar() | |

----------------| | | |---------------------| |
> > >

--------------------| | send publisher msg | | |
UpdateProgressBar()|<------------------------------------- |

(do ui fresh) | | |---------------------------|
--------------------| |

----------------------------|

it seems like wxpython are busy working on the events generated by Publisher(), it maybe has a much more higher priority compared to timer event or button clicked event?

···

On Fri, Nov 21, 2008 at 12:14 AM, jason zhang jason.gnu@gmail.com wrote:

On Thu, Nov 20, 2008 at 6:24 AM, Robin Dunn robin@alldunn.com wrote:

IIRC, timer events are relatively low priority so if there are other events pending then the timer events may not be sent until they have been processed. This may be part of what you are seeing. Another part may be that if the ui thread gets blocked waiting for some function to return then there will be no events delivered at all until the (relatively) long running task completes.

It’s not real clear from your code snippets but it looks like you may be breaking the thread rule. In a nutshell you should not invoke any function or method that accesses or manipulates a UI object from a thread that is not the UI thread. See http://wiki.wxpython.org/LongRunningTasks and http://wiki.wxpython.org/Non-Blocking_Gui

Robin Dunn

Software Craftsman

http://wxPython.org Java give you jitters? Relax with wxPython!

Robin,
the issue I’m suffering is the timer event seems has higher priority that other event such as EVT_BUTTON, and my event handler to handle pause button clicked have to wait for several timer events processed and caused a unexpected delayed response to user, and I’m not breaking the thread rule actually, I do all ui refresh operations in gui main thread, below is the event handle procedure for a timer event.

------MainWindow(gui)-------| |---------Controler---------|
> > >

----------------| | new worker thread | |---------------------| |
OnTimerEvent() |-----------------------------|->| UpdateProgressBar() | |

----------------| | | |---------------------| |
> > >

--------------------| | send publisher msg | | |
UpdateProgressBar()|<------------------------------------- |

(do ui fresh) | | |---------------------------|
--------------------| |

----------------------------|

jason zhang wrote:

    IIRC, timer events are relatively low priority so if there are other
    events pending then the timer events may not be sent until they have
    been processed. This may be part of what you are seeing. Another
    part may be that if the ui thread gets blocked waiting for some
    function to return then there will be no events delivered at all
    until the (relatively) long running task completes.

    It's not real clear from your code snippets but it looks like you
    may be breaking the thread rule. In a nutshell you should not
    invoke any function or method that accesses or manipulates a UI
    object from a thread that is not the UI thread. See
    LongRunningTasks - wxPyWiki and
    Non-Blocking Gui - wxPyWiki

    -- Robin Dunn
    Software Craftsman
    http://wxPython.org Java give you jitters? Relax with wxPython!

Robin, the issue I'm suffering is the timer event seems has higher priority that other event such as EVT_BUTTON, and my event handler to handle pause button clicked have to wait for several timer events processed and caused a unexpected delayed response to user, and I'm not breaking the thread rule actually, I do all ui refresh operations in gui main thread, below is the event handle procedure for a timer event.

Sending a publisher message does not do anything about the thread context that the subscriber is run in. It will use the same thread as the sendMessage() call, so unless I'm missing something, your "self.progress_bar.SetValue(percent)" is likely still happening in the worker thread.

it seems like wxpython are busy working on the events generated by Publisher(), it maybe has a much more higher priority compared to timer event or button clicked event?

Publisher doesn't use events and doesn't do any queuing of messages. When you call sendMessage it will call the subscribed functions immediately, before sendMessage returns.

···

On Thu, Nov 20, 2008 at 6:24 AM, Robin Dunn <robin@alldunn.com > <mailto:robin@alldunn.com>> wrote:

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Sending a publisher message does not do anything about the thread context that the subscriber is run in. It will use the same thread as the sendMessage() call, so unless I’m missing something, your “self.progress_bar.SetValue(percent)” is likely still happening in the worker thread.

it seems like wxpython are busy working on the events generated by Publisher(), it maybe has a much more higher priority compared to timer event or button clicked event?

Publisher doesn’t use events and doesn’t do any queuing of messages. When you call sendMessage it will call the subscribed functions immediately, before sendMessage returns.

Robin Dunn

Software Craftsman

http://wxPython.org Java give you jitters? Relax with wxPython!

I see, I got a stupid understanding of how Publisher() works, so send a custom event instead of a Publisher message will do the trick? Really appreciate your great help, thanks a lot.

jason zhang wrote:

    Sending a publisher message does not do anything about the thread
    context that the subscriber is run in. It will use the same
    thread as the sendMessage() call, so unless I'm missing something,
    your "self.progress_bar.SetValue(percent)" is likely still
    happening in the worker thread.

        it seems like wxpython are busy working on the events
        generated by Publisher(), it maybe has a much more higher
        priority compared to timer event or button clicked event?

    Publisher doesn't use events and doesn't do any queuing of
    messages. When you call sendMessage it will call the subscribed
    functions immediately, before sendMessage returns.

    -- Robin Dunn
    Software Craftsman
    http://wxPython.org Java give you jitters? Relax with wxPython!

I see, I got a *stupid* understanding of how Publisher() works, so send a custom event instead of a Publisher message will do the trick? Really appreciate your great help, thanks a lot.

You can use wx.CallAfter() to call the publisher module's sendMessage method because CallAfter is "thread-safe". There are other methods to do this sort of thing. Just browse the archives a bit. I recall one thread within the last month or two even.

Mike

You can use wx.CallAfter() to call the publisher module’s sendMessage method because CallAfter is “thread-safe”. There are other methods to do this sort of thing. Just browse the archives a bit. I recall one thread within the last month or two even.

Mike


wxpython-users mailing list

wxpython-users@lists.wxwidgets.org

http://lists.wxwidgets.org/mailman/listinfo/wxpython-users

Thanks Mike, that solution do saved me a lot of time refactoring my code, :slight_smile:

jason zhang wrote:

I see, I got a *stupid* understanding of how Publisher() works, so send a custom event instead of a Publisher message will do the trick?

wx.CallAfter uses an event to do its work, so it is an easy way to safely cause something to be executed in the context of the UI thread. You can also combine it with the use of the publisher if desired. (IOW, have the subscribed function call the real function using wx.CallAfter.)

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!