简体   繁体   中英

Why can't I initialize a QThread in a member function of class?

Here is the code:

##########################################################
######## Version 1 (works)
##########################################################
#!/usr/bin/env python3


from ui.qthreadtest import Ui_QthreadTest
from PySide import QtCore, QtGui
import time

class Md(QtGui.QDialog):
    def __init__(self):
        super().__init__()
        self.prcsbtn = QtGui.QPushButton("Process")
        self.prcsedit = QtGui.QLineEdit()
        layout = QtGui.QHBoxLayout()
        layout.addWidget(self.prcsedit)
        layout.addWidget(self.prcsbtn)
        self.setLayout(layout)
        self.prcsbtn.clicked.connect(self.work)

        self.wt = Worker()

    def work(self):
        self.wt.start()
        # the DirectConnection option demands the slot to be triggered immediately
        self.wt.workFinished.connect(self.changeText, QtCore.Qt.DirectConnection)

    def changeText(self):
        self.prcsedit.setText("Work finished!")

class Worker(QtCore.QThread):
    workFinished = QtCore.Signal()
    def __init__(self):
        super().__init__()

    def run(self):
        time.sleep(2)
        self.workFinished.emit()

import sys
app = QtGui.QApplication(sys.argv)
md = Md()
md.show()
sys.exit(app.exec_())


##########################################################
######## Version 2 (doesn't work)    
##########################################################

#!/usr/bin/env python3


from ui.qthreadtest import Ui_QthreadTest
from PySide import QtCore, QtGui
import time

class Md(QtGui.QDialog):
    def __init__(self):
        super().__init__()
        self.prcsbtn = QtGui.QPushButton("Process")
        self.prcsedit = QtGui.QLineEdit()
        layout = QtGui.QHBoxLayout()
        layout.addWidget(self.prcsedit)
        layout.addWidget(self.prcsbtn)
        self.setLayout(layout)
        self.prcsbtn.clicked.connect(self.work)


    def work(self):
        # the worker thread initialized in a member function won't work.
        wt = Worker()
        wt.start()
        # the DirectConnection option demands the slot to be triggered immediately
        wt.workFinished.connect(self.changeText, QtCore.Qt.DirectConnection)

    def changeText(self):
        self.prcsedit.setText("Work finished!")

class Worker(QtCore.QThread):
    workFinished = QtCore.Signal()
    def __init__(self):
        super().__init__()

    def run(self):
        time.sleep(2)
        self.workFinished.emit()

import sys
app = QtGui.QApplication(sys.argv)
md = Md()
md.show()
sys.exit(app.exec_())

Version 1 works ok, version 2 gives this error (while crushing instantly when the Process button is pressed):

QThread: Destroyed while thread is still running

Process finished with exit code 139

This is happening because unlike threading.Thread objects, QThread objects get destroyed as soon as they go out of scope. In your example, wt goes out of scope when work ends, so the object gets destroyed. To avoid this, you'll need to keep a lasting reference to wt . One way to do this would be to make it an instance variable:

def work(self):
    self.wt = Worker()
    self.wt.start()
    # the DirectConnection option demands the slot to be triggered immediately
    self.wt.workFinished.connect(self.changeText, QtCore.Qt.DirectConnection)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM