对象线程中的 PySide 插槽不是 运行

PySide slot not run in object's thread

我正在尝试 运行 在 PySide 的单独线程中执行一项长任务,以便主线程可以继续处理 GUI 事件。我读过正确的方法是:

但是,我 运行 遇到了一个奇怪的问题,如果 run() 方法被包装在一个槽中,函数将在主线程中 运行 而不是对象所属的线程。如果我将其保留为标准 Python 方法,一切正常。

这是我创建的一个最小示例:

#!/usr/bin/env python

import sys

from PySide import QtCore, QtGui


class Task(QtCore.QObject):
    """Does some work and emits a signal when done."""

    finished = QtCore.Signal(object)

    def run1(self):
        """Runs task and emits finished() signal when done."""
        try:
            # Try running the task
            result = self._run()

        except:
            self.finished.emit(None)

        else:
            self.finished.emit(result)

    @QtCore.Slot()
    def run2(self):
        """Same as run1, but wrapped in a slot."""
        self.run1()

    def _run(self):
        """Override in subclass"""
        pass


class TestTask(Task):
    """Prints thread ID."""

    def __init__(self, name):
        super().__init__()
        self.name = name

    def _run(self):
        print('{} thread ID:'.format(self.name), QtCore.QThread.currentThreadId())
        return 'success'


def main():

    gui = QtGui.QApplication([])

    print('Main thread ID: ', QtCore.QThread.currentThreadId())

    # thread1 calls task1.run1()
    task1 = TestTask('task1')
    task1.finished.connect(lambda r: print('Task 1 finished:', r))

    thread1 = QtCore.QThread()
    task1.moveToThread(thread1)

    thread1.started.connect(task1.run1)

    # thread2 calls task2.run2()
    task2 = TestTask('task2')
    task1.finished.connect(lambda r: print('Task 2 finished:', r))

    thread2 = QtCore.QThread()
    task2.moveToThread(thread2)

    thread2.started.connect(task2.run2)

    # Start both threads
    thread1.start()
    thread2.start()

    # Run event loop (doesn't actually return)
    sys.exit(gui.exec_())


if __name__ == '__main__':
    main()

这会产生以下输出:

Main thread ID:  139962303178496
task1 thread ID: 139961642776320
task2 thread ID: 139962303178496
Task 2 finished success
Task 1 finished success

run() 保留为标准 Python 方法并不是什么大问题,但我想知道为什么会这样。这是 QT4.8 和 PySide 1.2.4。

这可能是由 PySide 中的一个可能错误引起的。该问题似乎是由继承具有装饰槽的 base-class 引起的。如果将此槽移动到 subclass,问题就消失了:

class TestTask(Task):
    ...

    @QtCore.Slot()
    def run2(self):
        """Same as run1, but wrapped in a slot."""
        self.run1()

(PS:作为另一个数据点,值得注意的是您的原始示例在 PyQt4 中运行良好。

更新:

据推测,这是由 PySide 中的一个已知错误引起的:请参阅 PYSIDE-249