PySide: Easier way of updating GUI from another thread
multithreading, pyside, python, qt, signals-slots
Solution
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 QtCore
class 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 = kwargs
class 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.
Problem
I have a PySide (Qt) GUI which spawns multiple threads. The threads sometimes need to update the GUI. I have solved this in the following way: ``` class Signaller(QtCore.QObject) : my_signal = QtCore.Signal(QListWidgetItem, QIcon) signaller = Signaller() class MyThread(threading.Thread): def __init__(self): super(IconThread, self).__init__() # ... def run(self) : # ... # Need to update the GUI signaller.my_signal.emit(self.item, icon) # # MAIN WINDOW # class Main(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) # ... # Connect signals signaller.my_signal.connect(self.my_handler) @QtCore.Slot(QListWidgetItem, QIcon) def my_handler(self, item, icon): item.setIcon(icon) def do_something(self, address): # ... # Start new thread my_thread = MyThread(newItem) my_thread.start() # ... ``` Is there an easier way? Creating the signals, handlers and connect them requires a few lines of code.