我正在对线程应用程序进行故障排除,我注意到以下行为:在 PySide6 中,我想连接到插槽和非插槽方法,根据文档,这应该可以工作。然而它并没有按预期工作。我不确定这是一个错误还是我做错了什么?
QObject
,然后将其移动到槽内的新线程中,则当通过信号(使用 QObject
)调用时,QueuedConnection
的槽将不会在新线程中执行,然而,那些“不是”槽的方法却可以。如果先移动物体,然后连接起来,就一切正常了。
在PyQt5中,情况相反。不是槽的方法不会跟随 QObject
Dummy
对象移动到新线程中,然后尝试通过不同的机制调用带有按钮的
do_work
方法/do_work_slot
插槽,并检查执行该方法的线程。
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())
PySide6-6.6.1
升级到
PySide-6.7.1
有帮助。
我也签入了PyQt6-6.7.1
,它按预期工作。