PyQt5:如何让QThread将数据返回给主线程

时间:2015-03-24 21:59:09

标签: python multithreading qt

我是PyQt 5.4.1-1初学者,我的python是3.4.3。以下是我尝试按照正确的™方式关注many blogpostsSO问题制作线程(即没有QThread子类化):

#!/usr/bin/env python3

from PyQt5.QtCore import QObject, QThread
from PyQt5.QtCore import pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import QMainWindow

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        print("Base init")

        self.thread = QThread()
        w = Worker()
        w.finished[int].connect(self.onFinished)
        w.moveToThread(self.thread)
        self.thread.started.connect(w.work)
        self.thread.start()

    @pyqtSlot(int)
    def onFinished(self, i):
        print("Base caught finished, {}".format(i))

class Worker(QObject):
    finished = pyqtSignal(int)

    def __init__(self):
        print("Worker init")
        super().__init__()

    def work(self):
        print("Worker work")
        Worker.finished.emit(42)

if __name__ == "__main__":
    import sys
    from PyQt5.QtWidgets import QApplication

    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.show()

    sys.exit(app.exec_())

在写这个问题时,我意识到如果做出以下更改,那么一切似乎都有效:

...
self.w = Worker()
self.w.finished[int].connect(self.onFinished)
self.w.moveToThread(self.thread)
self.thread.started.connect(self.w.work)
...

...
self.finished.emit(42)
...

但我不明白为什么这会有所帮助。为什么我必须让非Gui相关的Worker实例成为Gui类的成员?坦白说,感觉不对劲。现在关于信号:它是class attribute那么为什么在运行时失败的Worker.finished.emit(42)调用与我预期没有差异的self.finisehd.emit(42)成功之间存在差异(&& #39; sa class属性!)

1 个答案:

答案 0 :(得分:1)

首先,Python是一种自动垃圾收集语言。您的变量w超出了__init__方法的范围,并在方法返回后立即进行垃圾回收。这就是为什么事情没有像你预期的那样第一次发挥作用的原因。使变量成为类的成员可确保在MainWindow实例存在时它不会超出范围。

你的第二个问题有点难以回答,但我敢打赌,通过查看QMetaObject文档,你将获得有关PySide / PyQt中信号如何工作的宝贵见解。

- 编辑 -

为您的第二个问题here找到了更好的答案。