简体   繁体   中英

QThread: Destroyed while thread is still running: How to proper use QThreads with QTimers?

I'm having a bit of a hassle of understanding what is happening in following test code.

I've created a timer which will go into a thread. This thread can be stopped within the object but when deployed in a main QT application, the thread somehow get's garbage collected when the main application ends.

Q: How can I proper stop the QThread before the main application ends.(Or implement the thread in a better way? )

import sys

from PySide6.QtCore import QTimer, Qt, QThread
from PySide6.QtWidgets import QWidget, QApplication, QLabel, QHBoxLayout

class Counter(QWidget):
    def __init__(self):
        super().__init__()

        self.cnt = 0

        self.timer = QTimer()
        self.timer.timeout.connect(self.__update_by_timer)

        self.label = QLabel()
        self.label.setText(str(self.cnt))

        self._layout = QHBoxLayout()
        self._layout.addWidget(self.label,  Qt.AlignCenter)
        self.setLayout(self._layout)

        self.timer.start(1000)
        self.thread = QThread()
        self.timer.moveToThread(self.thread)
        self.thread.start(QThread.Priority.LowestPriority)


    def __del__(self):
        self.thread.exit()

    def __update_by_timer(self):
        self.cnt += 1
        self.label.setText(str(self.cnt))

if __name__ == "__main__":

    app = QApplication(sys.argv)
    cnt = Counter()
    cnt.show()
    sys.exit(app.exec())

Main application screenshot:

在此处输入图像描述

I've found an answer to my problem,

The issue: If you click the app window away, there will be no call to the destructor of the "Counter" object so the timer within the thread lives somewhat apart from the GUI app.

To overcome this I've included a destructor which stops the timer and closes the thread. This must be called by the "closeEvent" method which must be derived from the QWidget class.

def __del__(self):
    self.timer.stop()
    self.thread.quit()

def closeEvent(self, event: QCloseEvent) -> None:
    ''' Derived method from QWidget '''
    self.__del__()
    super().closeEvent(event)

One extra caveat in the original code is the timer itself. This must be take the "Counter" class of a parent before this can be stopped in the destructor.

    self.timer = QTimer(self)

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