简体   繁体   中英

PyQt5 QThread does not stop neither with terminate or a flag variable

Hi I am developing a PyQt5 Application where the user can set a timer countdown. For updating the time label I use a QThread which emits a pyqtSignal every second in order to update the GUI/time label. This is my Code which uses QThread:

from PyQt5.QtCore import QThread, pyqtSignal, QObject import time

class Worker(QObject):
    update = pyqtSignal()
    stop = pyqtSignal()


class CountdownThread(QThread):
    def __init__(self, time_left):
        QThread.__init__(self)
        self.time_signal = Worker()
        self.time_left = time_left
        self.is_running = True


    def stop(self):
        self.is_running = False
        print(self.is_running)


    def run(self):
        while self.is_running:
            self.time_left -= 1
            time.sleep(1)
            self.time_signal.update.emit()
            if self.time_left == 0:
                self.stop()

With a button click the user should be able to stop the countdown and reset the GUI:

...

    def pressed_stop(self):
        self.start_stop_btn.setText("Start")
        self.start_stop_btn.clicked.connect(self.pressed_start)
        self.worker.stop() # self.worker is the QThread

...

When I click on the button the button text certainly does change to "Start". But the time label keeps counting down. Printing the is_running variable prints out False when clicking the button and therefore executing the self.worker.stop() function but keeps printing out True in the while loop of run() .

Initializing the CountdownThread is done here (after clicking start button):

...

    def count_down(self):
        self.worker = CountdownThread(self.time_left)
        self.worker.time_signal.update.connect(self.update_time_label)
        self.worker.time_signal.stop.connect(self.reset_timer)
        self.worker.start()

...

Why doesn't this work? I am running this application on Mac OS Catalina 10.15.4.

As some might have noticed, I am using the same button object for starting and stopping the countdown. I forgot to add

self.start_stop_btn.disconnect()

otherwise it would always call the countdown function again

The thing happening here is that your QThread spends all of its time in a while(True) loop, therefore it can never execute its stop() method before reaching the end of the countdown by the loop.

I think a similar thread exists that adresses the same question.

What you can do to circumvent the issue is to include in your loop a way to fetch the stop flag from your main thread.

A few recommendations:

  • Don't name a variable "worker" if you have a class named Worker: it's confusing
  • Instead of using time.sleep(xx) , I advise you to use QTimers for your application: they do the same but in a much easier way, and that would get rid of the while loop.
  • It is best practice to use signals and slots to communicate between threads (needed anyway for QTimer usage). Using them can get you through the while loop depending on the connection type (as it uses the event loop for QueuedConnection).
  • Although having a class that inherits from QThread works, it is recommended to create a classical QThread, have your tasks written in another class which extends QObject, then use the_QObject_extended_variable.moveToThread(the_QThread_variable)

Feel free to ask for examples if you need.

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