It does not matter if the connection was made before or after moving the work object to another thread. To quote Qt docs :
Qt :: AutoConnection - if a signal is emitted from a different thread than the receiving object, the signal is queued, behaves like Qt :: QueuedConnection. Otherwise, the slot is called directly, like Qt :: DirectConnection. Connection type: determined by the emission of a signal . [highlighted by me]
So, as long as the type connect argument is set to QtCore.Qt.AutoConnection (which is the default), Qt must ensure that the signals are emitted appropriately.
The problem with the sample code is more likely to be with a slot than a signal. The python method to which the signal is connected should probably be marked as a Qt slot using the pyqtSlot decorator :
from QtCore import pyqtSlot class Scanner(QObject): @pyqtSlot() def scan(self): scan_value(start, stop, step) progress.setValue(100)
EDIT
It should be clarified that only in fairly recent versions of Qt, the type of connection is determined by the emission of a signal. This behavior was introduced (along with several other changes to Qt's multithreading support) with version 4.4.
Also, it might be worthwhile to further expand the PyQt problem. In PyQt, a signal can be connected to a Qt slot, another signal, or any python called. In the latter case, an internal proxy object is created that wraps the called python and provides the slot that is required by the Qt signal / slot mechanism.
It is this proxy object that causes the problem. After creating the proxy, PyQt will simply do this:
if (rx_qobj) proxy->moveToThread(rx_qobj->thread());
which is fine if the connection is made after the receiving object has been transferred to its stream; but if this is done earlier, the proxy will remain in the main thread.
Using the @pyqtSlot decorator avoids this problem in general, since it creates a better Qt slot and does not use a proxy object at all.
Finally, it should also be noted that this issue does not currently affect PySide.