When a QObject
is created in a different thread and moved back to the main thread using QObject.moveToThread
, lambda
signals "disconnect" (they won't fire). My guess is that regular slots are linked to the QObject
that is moved to the main thread, so they run in the main thread's event loop, but lambda
functions aren't linked to the QObject
, so there is no event loop for them to run.
This can be seen in the following short Python code:
if __name__ == "__main__":
from traits.etsconfig.api import ETSConfig
ETSConfig.toolkit = 'qt4'
import threading
from PySide import QtGui, QtCore
class MyObject(QtCore.QObject):
def __init__(self, button):
super(MyObject, self).__init__()
button.clicked.connect(self.mySlot)
button.clicked.connect(lambda: self.mySlot('lambda'))
#
def mySlot(self, printing='object'):
print printing
#
myObj = None
# global variable to keep it in memory
def myThread(mainThread, button):
global myObj
myObj = MyObject(button)
myObj.moveToThread(mainThread)
#
if __name__ == '__main__':
appQT = QtGui.QApplication([])
#
myWidget = QtGui.QWidget()
myButton = QtGui.QPushButton('Press to see output')
myLayout = QtGui.QVBoxLayout(myWidget)
myLayout.addWidget(myButton)
myWidget.show()
#
mainThread = QtCore.QThread.currentThread()
if True:
# run myThread in a new thread
# prints only the first slot (object slot)
threading.Thread(target=myThread, args=[mainThread, myButton]).start()
else:
# run myThread in this thread
# prints both slots (object and lambda slots)
myThread(mainThread, myButton)
#
appQT.exec_()
You can see how the results differ from expected by changing the conditional from True
to False
.
When it is set to True
, the output after clicking the button is:
object
When it is set to False
, the output after clicking the button is:
object
lambda
My question is, can someone explain more precisely why it behaves in this way, and is there an easy way to keep the lambda
slots working when moving the QObject
back to the main thread?