`QObject.moveToThread` 在 PySide6 中不占用插槽

问题描述 投票:0回答:1

我正在对线程应用程序进行故障排除,我注意到以下行为:在 PySide6 中,我想连接到插槽和非插槽方法,根据文档,这应该可以工作。然而它并没有按预期工作。我不确定这是一个错误还是我做错了什么?

  • 在 PySide6 中,如果首先连接
    QObject
    ,然后将其移动到槽内的新线程中,则当通过信号(使用
    QObject
    )调用时,
    QueuedConnection
    的槽将不会在新线程中执行,然而,那些“不是”槽的方法却可以。如果先移动物体,然后连接起来,就一切正常了。 在PyQt5中,情况相反。不是槽的方法不会跟随
  • QObject
  • 进入新线程,但槽可以。我的理解是这是正确的,因为在 PyQt5 中,槽声明对于 QueuedConnection 的工作是必须的。
    
    
  • 我构建了一个最小的应用程序来说明问题。按顺序单击按钮将
Dummy

对象移动到新线程中,然后尝试通过不同的机制调用带有按钮的

do_work
方法/
do_work_slot
插槽,并检查执行该方法的线程。

Minimal application 在 PyQt5 中从上到下依次单击按钮会给出日志:

MainThread:move_to_thread: object thread: Main Thread, execution thread: Main Thread MainThread:do_work: object thread: new thread, execution thread: Main Thread MainThread:do_work: object thread: new thread, execution thread: Main Thread Dummy-1:do_work_slot: object thread: new thread, execution thread: new thread Dummy-1:do_work_slot: object thread: new thread, execution thread: new thread

而在 PySide6 中则是:

MainThread:move_to_thread: object thread: Main Thread, execution thread: Main Thread MainThread:do_work: object thread: new thread, execution thread: Main Thread Dummy-1:do_work: object thread: new thread, execution thread: new thread MainThread:do_work_slot: object thread: new thread, execution thread: Main Thread Dummy-1:do_work_slot: object thread: new thread, execution thread: new thread

请注意,对象的线程关联对于两个包都是正确的。
我在 PySide6 上期望的行为是(我添加了额外的星星以突出显示相关位)

MainThread:move_to_thread: object thread: Main Thread, execution thread: Main Thread MainThread:do_work: object thread: new thread, execution thread: Main Thread Dummy-1:do_work: object thread: new thread, execution thread: **new thread** **Dummy-1**:do_work_slot: object thread: new thread, execution thread: **new thread** Dummy-1:do_work_slot: object thread: new thread, execution thread: new thread

我附上申请表。

import logging import sys, os os.environ["QT_API"] = "pyqt5" # ""PySide6" from qtpy import QtCore, QtWidgets logging.basicConfig(format="%(asctime)s:%(levelname)s:%(threadName)s:%(name)s: %(message)s", level=logging.DEBUG) msg_template = "object thread: {thread1}, execution thread: {thread2}" class Dummy(QtCore.QObject): sigMoveToThread = QtCore.Signal() sigMoveToMain = QtCore.Signal() sigRequestWork = QtCore.Signal() def __init__(self, parent=None): QtCore.QObject.__init__(self, parent=parent) self.sigMoveToThread.connect(self.move_to_thread) self.sigMoveToMain.connect(self.move_to_main) self.sigRequestWork.connect(self.do_work_slot) def do_work(self): logging.info(msg_template.format( thread1=self.thread().objectName(), thread2=QtCore.QThread.currentThread().objectName() )) @QtCore.Slot() def do_work_slot(self): logging.info(msg_template.format( thread1=self.thread().objectName(), thread2=QtCore.QThread.currentThread().objectName() )) @QtCore.Slot() def move_to_thread(self): logging.info(msg_template.format( thread1=self.thread().objectName(), thread2=QtCore.QThread.currentThread().objectName() )) new_thread = QtCore.QThread() new_thread.setObjectName("new thread") self.moveToThread(new_thread) new_thread.start() self.t = new_thread # to avoid garbage collector if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) window = QtWidgets.QMainWindow() widget = QtWidgets.QWidget() layout = QtWidgets.QVBoxLayout() QtCore.QThread.currentThread().setObjectName("Main Thread") dummy = Dummy() # moving to thread at THIS stage as below would result in correct moving # of both Slot and non-Slot connection in PySide6 # thread = QtCore.QThread() # dummy.moveToThread(thread) button = QtWidgets.QPushButton("Click (Direct connection, not slot)") button.clicked.connect(dummy.do_work, QtCore.Qt.DirectConnection) layout.addWidget(button) button = QtWidgets.QPushButton("Click (Queued connection, not slot)") button.clicked.connect(dummy.do_work, QtCore.Qt.QueuedConnection) layout.addWidget(button) button = QtWidgets.QPushButton("Click (Queued connection, slot)") button.clicked.connect(dummy.do_work_slot, QtCore.Qt.QueuedConnection) layout.addWidget(button) button = QtWidgets.QPushButton("Click (sigRequestWork)") button.clicked.connect(dummy.sigRequestWork.emit) layout.addWidget(button) button = QtWidgets.QPushButton("Move to thread (move_to_thread slot)") button.clicked.connect(dummy.move_to_thread, QtCore.Qt.QueuedConnection) layout.addWidget(button) button = QtWidgets.QPushButton("Move to thread (sigMoveToThread)") button.clicked.connect(dummy.sigMoveToThread.emit, QtCore.Qt.QueuedConnection) layout.addWidget(button) widget.setLayout(layout) window.setCentralWidget(widget) window.show() sys.exit(app.exec())

	
qt pyqt5 signals-slots qthread pyside6
1个回答
0
投票
PySide6-6.6.1

升级到

PySide-6.7.1
有帮助。 我也签入了
PyQt6-6.7.1
,它按预期工作。
    

© www.soinside.com 2019 - 2024. All rights reserved.