PyQt5 QThread 不会因终止或标志变量而停止

Posted

技术标签:

【中文标题】PyQt5 QThread 不会因终止或标志变量而停止【英文标题】:PyQt5 QThread does not stop neither with terminate or a flag variable 【发布时间】:2020-08-04 14:27:14 【问题描述】:

您好,我正在开发一个 PyQt5 应用程序,用户可以在其中设置计时器倒计时。为了更新时间标签,我使用 QThread 每秒发出一个 pyqtSignal 以更新 GUI/时间标签。这是我使用 QThread 的代码:

从 PyQt5.QtCore 导入 QThread、pyqtSignal、QObject 进口时间

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()

通过单击按钮,用户应该能够停止倒计时并重置 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

...

当我单击按钮时,按钮文本确实会变为“开始”。但时间标签一直在倒计时。打印is_running 变量会在单击按钮并因此执行self.worker.stop() 函数时打印出False,但在run()while 循环中继续打印出True

在这里初始化CountdownThread(点击开始按钮后):

...

    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()

...

为什么这不起作用? 我在 Mac OS Catalina 10.15.4 上运行此应用程序。

【问题讨论】:

【参考方案1】:

有些人可能已经注意到,我使用相同的按钮对象来开始和停止倒计时。忘记加了

self.start_stop_btn.disconnect()

否则总是会再次调用倒计时函数

【讨论】:

【参考方案2】:

这里发生的事情是,您的 QThread 将所有时间都花在了 while(True) 循环中,因此在循环倒计时结束之前,它永远无法执行其 stop() 方法。

我认为存在解决相同问题的类似主题。

您可以做些什么来规避这个问题是在您的循环中包含一种从您的主线程中获取停止标志的方法。

一些建议:

如果您有一个名为 Worker 的类,请不要将变量命名为“worker”:这会造成混淆 我建议您不要使用time.sleep(xx),而是将QTimers 用于您的应用程序:它们的作用相同,但方式更简单,这样可以摆脱while 循环。 最佳实践是使用信号和槽在线程之间进行通信(无论如何都需要使用 QTimer)。使用它们可以让您完成 while 循环,具体取决于连接类型(因为它使用 QueuedConnection 的事件循环)。 虽然有一个继承自 QThread 的类可以工作,但建议创建一个经典的 QThread,将你的任务写在另一个扩展 QObject 的类中,然后使用the_QObject_extended_variable.moveToThread(the_QThread_variable)

如果需要,请随时询问示例。

【讨论】:

见this thread我的建议代码示例:

以上是关于PyQt5 QThread 不会因终止或标志变量而停止的主要内容,如果未能解决你的问题,请参考以下文章

在 QTimer Singleshot 之后终止 QThread

PyQt5 - 即使使用 QThread,MainWindow 中的 QMovie 也无法播放

PyQt5:使用 QObject 和 QThread 时出现 AttributeError

Firebase 的 Cloud Functions 因超出内存限制而被终止

如何在应用程序退出()期间处理 Qthread 终止?

python pyqt5 QThread