Python 在使用PyQt5的正确线程中未接收到信号
因此,在充分理解了如何正确使用Qt中的线程之后,我编写了一个小玩具示例,其中一个Python 在使用PyQt5的正确线程中未接收到信号,python,multithreading,qt,pyqt,pyqt5,Python,Multithreading,Qt,Pyqt,Pyqt5,因此,在充分理解了如何正确使用Qt中的线程之后,我编写了一个小玩具示例,其中一个QObject被移动到一个正在运行的线程,当单击窗口时,该对象上会调用一个信号 我遇到的问题是插槽从来没有在正确的线程中调用过——它总是在主线程中调用 这是通过以下代码实现的: from PyQt5 import QtWidgets, QtCore class WidgetWithInput(QtWidgets.QWidget): widgetClicked = QtCore.pyqtSignal()
QObject
被移动到一个正在运行的线程,当单击窗口时,该对象上会调用一个信号
我遇到的问题是插槽从来没有在正确的线程中调用过——它总是在主线程中调用
这是通过以下代码实现的:
from PyQt5 import QtWidgets, QtCore
class WidgetWithInput(QtWidgets.QWidget):
widgetClicked = QtCore.pyqtSignal()
def mousePressEvent(self, event):
self.widgetClicked.emit()
class MyObject(QtCore.QObject):
aSignal = QtCore.pyqtSignal()
def __init__(self, *args, **kwargs):
super(MyObject, self).__init__(*args, **kwargs)
self.aSignal.connect(self.onASignal)
def onASignal(self):
print('MyObject signal thread: %s'
% str(int(QtCore.QThread.currentThreadId())))
class SimpleDisplay(QtWidgets.QMainWindow):
''' Class presenting the display subsytem
'''
def __init__(self, my_object, *args, **kwargs):
super(SimpleDisplay, self).__init__(*args, **kwargs)
self._my_object = my_object
self._widget = WidgetWithInput()
self.setCentralWidget(self._widget)
self._widget.widgetClicked.connect(self._do_something)
def _do_something(self):
self._my_object.aSignal.emit()
def main(run_until_time=None):
import sys
app = QtWidgets.QApplication(sys.argv)
print ('main thread: %s' % str(int(QtCore.QThread.currentThreadId())))
concurrent_object = MyObject()
display = SimpleDisplay(concurrent_object)
myobject_thread = QtCore.QThread()
myobject_thread.start()
concurrent_object.moveToThread(myobject_thread)
display.show()
exit_status = app.exec_()
myobject_thread.quit()
myobject_thread.wait()
sys.exit(exit_status)
if __name__ == '__main__':
main()
其输出类似于:
main thread: 139939383113472
MyObject signal thread: 139939383113472
我希望这两个打印的线程ID是不同的
我是不是遗漏了什么?显式设置要排队的信号不会改变任何事情。多亏了@three_pinapples,他在评论中的建议解决了这个问题:插槽需要用
QtCore.pyqtlot
装饰:
class MyObject(QtCore.QObject):
aSignal = QtCore.pyqtSignal()
def __init__(self, *args, **kwargs):
super(MyObject, self).__init__(*args, **kwargs)
self.aSignal.connect(self.onASignal)
@QtCore.pyqtSlot()
def onASignal(self):
print('MyObject signal thread:\t %s'
% str(int(QtCore.QThread.currentThreadId())))
感谢@three_pinapples,他在评论中的建议解决了这个问题:插槽需要用
QtCore.pyqtlot
装饰:
class MyObject(QtCore.QObject):
aSignal = QtCore.pyqtSignal()
def __init__(self, *args, **kwargs):
super(MyObject, self).__init__(*args, **kwargs)
self.aSignal.connect(self.onASignal)
@QtCore.pyqtSlot()
def onASignal(self):
print('MyObject signal thread:\t %s'
% str(int(QtCore.QThread.currentThreadId())))
在将
MyObject
实例移动到新线程之前,您似乎正在触发MyObject.aSignal
信号。因此,您看到的输出。@G.M.我理解信号是在对象的线程中接收的。我很高兴在这一点上错了,但我不清楚如何将信号连接到正确的线程中。我尝试了几件事,比如在ThreadChange
事件上发出一个新的信号(这在概念上是线程更改之前的最后一个事件),一个连接信号的处理程序,但没有起作用(与之前的结果相同)。我可以通过在main
函数中显式地执行它来让它工作,但这需要我的main
具备应该限制在IMO类的知识。此外,我可以通过将线程传递到MyObject
来解决问题,然后在\uuuu init\uuuu
中使用self.moveToThread
。这对我来说似乎有点麻烦,因为它需要MyObject知道它所在的线程。除非用pyqtSlot
函数装饰插槽,否则连接信号和将对象移动到线程的顺序很重要。我将其标记为(请参阅)副本的问题是针对PyQt4,但我相信它也会转换为PyQt5。在将MyObject
实例移动到新线程之前,您似乎正在触发MyObject.aSignal
信号。因此,您看到的输出。@G.M.我理解信号是在对象的线程中接收的。我很高兴在这一点上错了,但我不清楚如何将信号连接到正确的线程中。我尝试了几件事,比如在ThreadChange
事件上发出一个新的信号(这在概念上是线程更改之前的最后一个事件),一个连接信号的处理程序,但没有起作用(与之前的结果相同)。我可以通过在main
函数中显式地执行它来让它工作,但这需要我的main
具备应该限制在IMO类的知识。此外,我可以通过将线程传递到MyObject
来解决问题,然后在\uuuu init\uuuu
中使用self.moveToThread
。这对我来说似乎有点麻烦,因为它需要MyObject知道它所在的线程。除非用pyqtSlot
函数装饰插槽,否则连接信号和将对象移动到线程的顺序很重要。我将其标记为(请参阅)的副本的问题是针对PyQt4的,但我相信它也会转换为PyQt5。