Search code examples
pythonpyqtpyqt5qthreadqtimer

PyQt5 QTimer in QThread is being "garbage collected"?


I'm trying to use a QTimer in a QThread but it doesn't call the function I need it to call. I read something about garbage collection and that the timer is being thrown out before it has a chance to be used (from my understanding). I tried the many ways I found in other code examples but I'm misunderstanding something as those examples didn't help.

The run() method is triggered by a button from the Main_Window class. Moving the instantiation of the timer to the run() method didn't help. What is the problem here?

#Main_Window class is here

class TheThread(QThread):

    def __init__(self, Main_Window):
        QThread.__init__(self)

        #some code above
        self.timeTaken = 0
        self.myTimer = QTimer()
        self.myTimer.timeout.connect(self.track_time)

    def track_time(self):
        #Not being called
        self.timeTaken += 0.1

    def run(self):
        #some code above
        self.myTimer.start(1000)
        #code in a while loop below

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = Main_Window()
    sys.exit(app.exec_())

Solution

  • While @eyllanesc's answer works, the run method already contains an event loop (as long as you don't override it!). So you could instead do:

    class TheThread(QtCore.QThread):
        def __init__(self, Main_Window):
            QtCore.QThread.__init__(self)
            #some code above
            self.timeTaken = 0
            self.myTimer = QtCore.QTimer()
            self.myTimer.moveToThread(self)
            self.myTimer.timeout.connect(self.track_time)
            # once the thread starts, the started signal is emitted
            self.started.connect(self.start_timer)
            # start the thread, which will emit the above signal!
            self.start()
    
        def start_timer(self):
            self.myTimer.start(1000)
    
        def track_time(self):
            self.timeTaken += 0.1
            print(self.timeTaken)