【发布时间】:2016-04-28 05:26:23
【问题描述】:
当QObject 在另一个线程中创建并使用QObject.moveToThread 移回主线程时,lambda 发出“断开连接”信号(它们不会触发)。我的猜测是常规插槽链接到移动到主线程的QObject,因此它们在主线程的事件循环中运行,但lambda函数没有链接到QObject,所以没有让它们运行的事件循环。
这可以在以下简短的 Python 代码中看到:
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_()
您可以通过将条件从 True 更改为 False 来查看结果与预期有何不同。
设置为True时,点击按钮后的输出为:
object
设置为False时,点击按钮后的输出为:
object
lambda
我的问题是,有人可以更准确地解释为什么它会以这种方式运行,当将 QObject 移回主线程时,是否有一种简单的方法可以保持 lambda 插槽正常工作?
【问题讨论】:
-
尝试用
lambda self=self: self.mySlot('lambda')替换lambda: self.mySlot('lambda');我认为您遇到了范围问题。 -
谢谢 chepner,我刚试过,但结果相同,所以这似乎不是问题。
-
从来没有在Qt中使用过Python,甚至没有过多地使用Python本身,但是你不认为lambda连接是用一些隐藏的QObject实现的吗?尝试在该线程中添加一个事件循环,也许它会出现。此外,您可以使用 GDB 进行探索,Qt C++ 代码非常易于调试,尤其是在您使用 Debian 之类的软件时。
-
感谢 Velkan 的评论,这将是一个很好的下一步,将 Python 线程更改为 QThreads,看看会发生什么。有机会我会试试这个。
标签: python multithreading qt lambda