代码之家  ›  专栏  ›  技术社区  ›  JaredL

PySide插槽未在对象的线程中运行

  •  3
  • JaredL  · 技术社区  · 7 年前

    • 将任务封装在 QObject 子类,其中工作在 run() finished 完成后发出信号。
    • QThread 并使用 QObject.moveToThread() .
    • start 向任务的 方法
    • QThread.start() .

    然而,我遇到了一个奇怪的问题,如果 方法包装在一个槽中,函数将在主线程中运行,而不是在对象所属的线程中运行。如果我把它作为标准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
    

    作为一种标准的Python方法,但我想知道为什么会发生这种情况。这是QT4.8和PySide 1.2.4。

    1 回复  |  直到 7 年前
        1
  •  3
  •   ekhumoro    7 年前

    这可能是由PySide中可能存在的错误引起的。这个问题似乎是由于继承了具有装饰槽的基类引起的。如果将此槽移到子类中,问题就会消失:

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

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

    :

    正如所怀疑的那样,这是由PySide中的一个已知错误引起的:请参阅 PYSIDE-249 .