Updating GUI from sub-threads

Hello,

Ive got a threaded application, where sub-threads sometimes needs to update
the GUI. Im using the following mechanism to accomplish this in a thread-safe
way.

···

---
__EVT_THREAD__ = wx.NewEventType()

class ThreadEvent(wx.PyEvent):
    def __init__(self, func, *args, **kwargs):
        wx.PyEvent.__init__(self)
        self.SetEventType(__EVT_THREAD__)
        self.__func = func
        self.__args = args
        self.__kwargs = kwargs

    def execute(self):
        self.__func(*self.__args, **self.__kwargs)

def popMessageDialog(self, cap, msg, style=wx.OK|wx.ICON_ERROR|wx.CENTRE):
        """
        Method for popping message dialog from thread
        """
        dlg = wx.MessageDialog(self.frame,
                               message='%s' % msg,
                               caption='%s' % cap,
                               style=style)

        wx.PostEvent(self.frame, ThreadEvent(dlg.ShowModal))

---

This is an excerpt, but you get the idea. Im calling popMessageDialog from my
threads.

This almost always works, however sometimes the dialog will come up with no
widgets inside and the GUI will then not be updated anymore. You can infact
still press the OK button if you know where its located in the message
dialog, but no GUI updates are performed after this - not even in the main
window (Tested on GNU/Linux both wx-2.6 and wx-2.8, and no difference).

Ive got lots of other GUI update methods called from threads too in a similar
way as popMessageDialog, and they all work as expected and never cause any
similar problems.

Any input greatly appreciated.

Best regards,
Frank Aune

Hi Frank,

       wx.PostEvent(self.frame, ThreadEvent(dlg.ShowModal))

This is an excerpt, but you get the idea. Im calling popMessageDialog from my
threads.

This almost always works, however sometimes the dialog will come up with no
widgets inside and the GUI will then not be updated anymore. You can infact
still press the OK button if you know where its located in the message
dialog, but no GUI updates are performed after this - not even in the main
window (Tested on GNU/Linux both wx-2.6 and wx-2.8, and no difference).

I believe you need to be careful about threading and using dialog with
ShowModal(). With ShowModal the program flow does not return until the
dialog has been dismissed (destroying the dialog, calling EndModal,
whatever), and this might be an issue with threading. I am not that
expert in this field, but I'd better avoid calling a blocking widget
within a thread.
A part of that, if you can provide a snippet of working code, I am
sure others will come up with better suggestions.

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.virgilio.it/infinity77/

···

On 4/27/07, Frank Aune wrote:

Actually I found a place in my subthread which updated the GUI directly, and it triggered the described effect after some time. Really tricky business, so I see why this is frown upon.

But this leads me to more question (yaaay :slight_smile: :

When posting events that a GUI update is pending, can I only do atomic updates or can I post an event and then run the threaded operation from start to end?

Is there any way I can "surrender" my main GUI control completely to the subthread?

-Frank

···

Den 27. apr. 2007 kl. 18.00 skrev Josiah Carlson:

Frank Aune <Frank.Aune@broadpark.no> wrote:

Hello,

Ive got a threaded application, where sub-threads sometimes needs to update
the GUI. Im using the following mechanism to accomplish this in a thread-safe
way.

Creating widgets, calling methods, etc., is generally sketchy when done
from a non-mainthread. Instead, if you create some method that creates
the dialog and shows it, then run it in the mainthread (either with your
event mechanism, or the built-in equivalent of wx.CallAfter()), you will
likely find that it works pretty well.

- Josiah

Frank Aune wrote:

Getting alot of:
Xlib: unexpected async reply (sequence 0x10300)!

And this has always indicated a direct access to the main loop from subthreads for me. I know its impossible for you to debug any more without access to the code, but do you know why I might see these differences?

Something is still creating/updating/accessing the GUI from a non-gui thread that shouldn't be. IIRC this message means that there is a response from the X-Server to the app that arrives when some other thread has control than the one that sent the message the response is for.

You'll really be better off to do *everything* related to the UI from the gui thread, using wx.CallAfter or some other event posting mechanism from the worker threads as needed.

···

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

Frank Aune wrote:

Getting alot of:
Xlib: unexpected async reply (sequence 0x10300)!

And this has always indicated a direct access to the main loop from subthreads for me. I know its impossible for you to debug any more without access to the code, but do you know why I might see these differences?

Something is still creating/updating/accessing the GUI from a non-gui
thread that shouldn't be. IIRC this message means that there is a
response from the X-Server to the app that arrives when some other
thread has control than the one that sent the message the response is for.

You'll really be better off to do *everything* related to the UI from
the gui thread, using wx.CallAfter or some other event posting mechanism
from the worker threads as needed.

···

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

And using wx.CallAfter is so simple and transparent there's no
excuse for not using it.

···

On 2007-04-28, Robin Dunn <robin@alldunn.com> wrote:

You'll really be better off to do *everything* related to the UI from
the gui thread, using wx.CallAfter or some other event posting mechanism
from the worker threads as needed.

--
Grant Edwards grante Yow! By MEER biz doo
                                  at SCHOIN...
                               visi.com