[PyQt] Signals across threads

Phil Thompson phil at riverbankcomputing.co.uk
Fri Aug 10 17:11:29 BST 2007


On Wednesday 08 August 2007 3:15 pm, Gwendolyn van der Linden wrote:
> Hi,
>
> I'm using PyQt4, version 4.2.3, on Windows XP.  It seems that signals
> emit()'ed from the GUI thread are delivered to other threads in the GUI
> thread, rather than in the target thread.  The following program
> demonstrates this:
>
> -------------------------
>
> import sys
> from PyQt4 import QtGui, QtCore
>
> class WorkerThread(QtCore.QThread):
>     def __init__(self):
>         QtCore.QThread.__init__(self)
>     def slotDo(self):
>         print 'slotDo called in thread:', self.currentThread()
>         self.emit(QtCore.SIGNAL('done'))
>     def run(self):
>         print 'Worker thread:', self.currentThread()
>         self.exec_()
>
> class MainWindow(QtGui.QMainWindow):
>     def __init__(self):
>         self.i = 1
>         QtGui.QMainWindow.__init__(self)
>         self.widget = QtGui.QPushButton('Do %i' % self.i)
>         self.connect(self.widget, QtCore.SIGNAL('clicked()'),
> self.slotClicked)
>         self.setCentralWidget(self.widget)
>     def slotClicked(self):
>         self.emit(QtCore.SIGNAL('do'))
>     def slotDone(self):
>         self.i += 1
>         self.widget.setText('Do %i' % self.i)
>
> def main(args):
>     app = QtGui.QApplication(sys.argv)
>     win = MainWindow()
>     win.show()
>     worker = WorkerThread()
>     worker.start()
>     app.connect(win, QtCore.SIGNAL('do'), worker.slotDo)
>     app.connect(worker, QtCore.SIGNAL('done'), win.slotDone)
>     print 'Main thread:', app.instance().thread()
>     app.exec_()
>
> if __name__ == "__main__":
>     main(sys.argv)
>
> -------------------------
>
> This gives (after clicking the button once):
>
>   Main thread: <PyQt4.QtCore.QThread object at 0x009E78E8>
>   Worker thread: <__main__.WorkerThread object at 0x009E78A0>
>   slotDo called in thread: <PyQt4.QtCore.QThread object at 0x009E78E8>
>
> As you can see, the 'slotDo' method from the worker thread is called
> from the GUI thread.  This behaviour means that time consuming code in
> the worker thread slots will block the GUI.  I was under the impression
> that the signal/slot mechanism is supposed to see that 'win' and
> 'worker' are in two different threads, and that the event loop in the
> worker thread will catch the emit()'ed signal.
>
> Is this a bug, or am I missing something here?

win and worker are not in two different threads - they both live in the thread 
in which they were created, ie. the main thread.

Signals are delivered in the thread in which the receiving object lives.

You need to create a new object in the run() method and use that to provide a 
slot. The attached modification to your example demonstrates this.

Phil
-------------- next part --------------
A non-text attachment was scrubbed...
Name: bug.py
Type: application/x-python
Size: 1220 bytes
Desc: not available
Url : http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20070810/2ee1ea60/bug.bin


More information about the PyQt mailing list