Search code examples
pythonpyqtpyqt5signals-slotsqthread

Terminate a QThread after QTimer Singleshot


I've got an issue. I'm running a PyQt5 form that runs a worker called Task() (I won't get into the details of its code, but it basically just returns a value to a QLabel) in a QThread like so:

class Menu(QMainWindow):
    def __init__(self, workers):
        super().__init__()
        self.central_widget = QWidget()               
        self.setCentralWidget(self.central_widget)    
        lay = QVBoxLayout(self.central_widget)
        self.setFixedSize(500, 350)
        Pic = QLabel(self)
        self.Total = QLabel("Total: <font color='orange'>%s</font>" % (to_check()), alignment=QtCore.Qt.AlignHCenter)
        lay.addWidget(self.Total)
        thread = QtCore.QThread(self)
        thread.start()
        self.worker = Task()
        self.worker.moveToThread(thread)
        self.worker.totalChanged.connect(self.updateTotal)
        QtCore.QTimer.singleShot(0, self.worker.dostuff)
        thread.finished.connect(self.terminate)


    @QtCore.pyqtSlot(int)
    def updateTotal(self, total):
        self.Total.setText("Total: <font color='orange'>%s</font>" % (total))  

    def terminate(self):
        print("FINISHED")
        self.worker.quit()
        self.worker.wait()
        self.close()

What I'd like is for the program to call the terminate slot (and basically terminate the thread and function) once the Task().dostuff() function is finished - but I can't seem to make it work.

I'm not sure how I can return to the main function through QTimer.singleshot.


Solution

  • A timer shouldn't be needed. Use the thread's started signal to start the worker, and add a finished signal to the worker class to quit the thread:

    class Task(QtCore.QObject):
        totalChanged = QtCore.pyqtSignal(int)
        finished = QtCore.pyqtSignal()
    
        def dostuff(self):
            # do stuff ...
            self.finished.emit()
    
    class Menu(QtWidgets.QMainWindow):
        def __init__(self, workers):
            super().__init__()
            ...
            self.thread = QtCore.QThread()
            self.worker = Task()
            self.worker.moveToThread(self.thread)
            self.worker.totalChanged.connect(self.updateTotal)
            self.worker.finished.connect(self.thread.quit)
            self.thread.started.connect(self.worker.dostuff)
            self.thread.start()