PySide: Easier way of updating GUI from another thread
I started coding with PySide recently and I needed a equivalent of PyGObject's GLib.idle_add
behaviour. I based the code off of your answer ( https://stackoverflow.com/a/11005204/1524507 ) but this one uses events instead of using a queue ourselves.
from PySide import QtCoreclass InvokeEvent(QtCore.QEvent): EVENT_TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) def __init__(self, fn, *args, **kwargs): QtCore.QEvent.__init__(self, InvokeEvent.EVENT_TYPE) self.fn = fn self.args = args self.kwargs = kwargsclass Invoker(QtCore.QObject): def event(self, event): event.fn(*event.args, **event.kwargs) return True_invoker = Invoker()def invoke_in_main_thread(fn, *args, **kwargs): QtCore.QCoreApplication.postEvent(_invoker, InvokeEvent(fn, *args, **kwargs))
Which is used the same way in the above answer link.
This is what I have so far. I wrote the following code somewhere in a helper module:
from Queue import Queueclass Invoker(QObject): def __init__(self): super(Invoker, self).__init__() self.queue = Queue() def invoke(self, func, *args): f = lambda: func(*args) self.queue.put(f) QMetaObject.invokeMethod(self, "handler", QtCore.Qt.QueuedConnection) @Slot() def handler(self): f = self.queue.get() f()invoker = Invoker()def invoke_in_main_thread(func, *args): invoker.invoke(func,*args)
Then my threads can very easily run code to update the GUI in the main thread. There is no need to create and connect signals for every operation.
class MyThread(threading.Thread): def __init__(self): super(IconThread, self).__init__() # ... def run(self) : # ... # Need to update the GUI invoke_in_main_thread(self.item.setIcon, icon)
I think something like this is quite nice.