pythoneventsqtimerpyqt6

PyQt6: Use QTimer to run a loop for a few seconds before stopping


I want to run a python while-loop for x amount of time (2 seconds) and then stop:

from PyQt6 import QtCore


def loop():
    stop = False

    def stop_loop():
        nonlocal stop
        stop = True
        print('STOPPING LOOP')

    timer = QtCore.QTimer()
    timer.setSingleShot(True)
    timer.setInterval(2000)
    timer.timeout.connect(stop_loop)
    timer.start()
    counter = 0
    while 1:
        counter += 1
        print(counter)
        if stop:
            break


app = QtCore.QCoreApplication([])
loop()
app.exec_()

But the loop keeps running infinitely and never stops.


Solution

  • The QTimer posts an event to the event-queue when it times-out, but your while-loop blocks all processing of events, so the timer-event never gets processed. To get your example to work, you would need to periodically force processing of any pending events:

    def loop():
        ...
        while 1:
            counter += 1
            print(counter)
            # clear event-queue
            app.processEvents()
            if stop:
                break
            # do some more work...
            QtCore.QThread.msleep(100)
    

    Whilst this method works for some simple cases, it's not usually very scalable, so the preferred approach is to move the blocking task into a separate worker thread, like this:

    from PyQt6 import QtCore   
    
    class Thread(QtCore.QThread):
        def stop(self):
            self._stopped = True
            print('STOPPING LOOP')
    
        def run(self):
            self._stopped = False
            counter = 0
            while not self._stopped:
                counter += 1
                print(counter)
                # do some more work...
                self.msleep(100)
    
    app = QtCore.QCoreApplication(['Test'])
    
    thread = Thread()
    thread.finished.connect(app.quit)
    QtCore.QTimer.singleShot(2000, thread.stop)
    thread.start()
    
    app.exec()