Why the QThread behave different if create it as l

2020-02-06 17:04发布

I have found a strange behavior if I create QThread as local variable.

For example, the following code will work as single thread, which means I need to wait 10 seconds and the result will come out.

But if I change thread from local variable to member variable, it works as multi thread.

How's it coming? Could anyone give me some tips?

class UI():
    def __init__(self):
        self.app = QtGui.QApplication(sys.argv)
        self.dialog = QtGui.QDialog()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self.dialog)
        self.ui.btn.clicked.connect(self.btnclick)

    def run(self):
        self.dialog.show()
        sys.exit(self.app.exec_())

    def btnclick(self):
        ## if change to self.thread, the behavior changes!!
        signal = QtCore.SIGNAL("Log(QString)")
        thread = testThread(signal)  
        QtCore.QObject.connect(thread, signal, self.output)
        thread.start()

    def output(self, txt):
        self.ui.logText.append(str(txt))

class testThread(QThread):
    def __init__(self, signal):
        QThread.__init__(self)
        self.signal = signal

    def __del__(self):
        self.wait()

    def run(self):
        for i in range(10):
            time.sleep(1)
            self.output(str(i))

    def output(self, txt):
        self.emit(self.signal, txt)


if __name__ == "__main__":
    ui = UI()
    ui.run()

1条回答
叛逆
2楼-- · 2020-02-06 17:27

The problem as to point out is that it is a local variable that will be destroyed a moment after having started the QThread so the thread that is handled by QThread(QThread is not a thread, it is a thread handler) will be removed and when using wait() it is expected that run() method will be executed but in the main thread generating the GUI s freeze.

So the solution is to extend the life of the variable thread, one way you point out that it works: make it a member of the class, but there is another way that only works with QObjects as QThread and that is to pass a parent (the parent must to be another QObject) that will extend the life of the object to the same capacity of the parent, for that reason I will use a dialog.

Finally nowadays it is not recommended to create signals dynamically, it is better to create it as part of a class, also for the connection you must use the new syntax.

class UI():
    def __init__(self):
        self.app = QtGui.QApplication(sys.argv)
        self.dialog = QtGui.QDialog()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self.dialog)
        self.ui.btn.clicked.connect(self.btnclick)
        self.dialog.show()

    def btnclick(self):
        thread = testThread(self.dialog)  
        thread.signal.connect(self.output)
        thread.start()

    def output(self, txt):
        self.ui.logText.append(str(txt))

class testThread(QtCore.QThread):
    signal = QtCore.pyqtSignal(str)

    def __del__(self):
        self.wait()

    def run(self):
        for i in range(10):
            QtCore.QThread.sleep(1)
            self.output(str(i))

    def output(self, txt):
        self.signal.emit(txt)

if __name__ == '__main__':
    ui = UI()
    app = QtGui.QApplication.instance()
    if app is not None:
        sys.exit(app.exec_())
查看更多
登录 后发表回答