You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5中QTimer启动后无法执行update_label函数的问题求助

PyQt5 QTimer在QRunnable中无法触发timeout的问题解决

问题根源

  1. QRunnable线程生命周期问题:QRunnable的run方法执行完毕后,线程会被线程池立即回收,QTimer刚启动就失去了运行上下文,根本没机会触发timeout信号。
  2. 事件循环缺失:QTimer依赖Qt的事件循环才能工作,但QRunnable所在的子线程默认没有启动事件循环,即便run方法不结束,Timer也无法正常触发回调。

解决方案

方案一:用QThread替代QRunnable(推荐)

QThread自带事件循环,适合长期运行的定时任务,代码结构更稳定:

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import pyqtSlot, QThread, pyqtSignal

class WorkerSignal(QtCore.QObject):
    latest_number = pyqtSignal(str)

class Updater(QThread):
    def __init__(self):
        super(Updater, self).__init__()
        self.update_progress = WorkerSignal()
        print("started")

    def run(self):
        self.timer = QtCore.QTimer()
        self.timer.setInterval(2000)
        self.timer.timeout.connect(self.update_label)
        self.timer.start()
        # QThread的exec_()会启动事件循环,保持线程持续运行
        self.exec_()

    def update_label(self):
        provider = configfile.provider
        number = str(nmbr.latest_numer(provider))
        self.update_progress.latest_number.emit(number)
        print("update label started")

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        
        self.setObjectName("MainWindow")
        self.resize(1300, 768)
        self.setMinimumSize(1300,768)
        _translate = QtCore.QCoreApplication.translate
        self.setWindowTitle(_translate("Bot", "Bot"))
        
        self.number = QtWidgets.QLabel(self)
        self.number.setGeometry(QtCore.QRect(1100, 10, 300, 20))
        self.number.setObjectName("number")
        
        self.show()
        
        self.updater = Updater()
        self.updater.update_progress.latest_number.connect(self.update_number)
        self.updater.start()

    @pyqtSlot(str)
    def update_number(self, val):
        self.number.setText(f"Current block: {val}")

方案二:在QRunnable中手动启动事件循环

如果一定要用QRunnable,需要在run方法里启动事件循环,让线程保持运行:

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import pyqtSlot, QRunnable, QEventLoop

class WorkerSignal(QtCore.QObject):
    latest_number = pyqtSignal(str)

class Updater(QRunnable):
    def __init__(self):
        super(Updater, self).__init__()
        self.update_progress = WorkerSignal()
        self.is_running = True
        print("started")

    def run(self):
        self.timer = QtCore.QTimer()
        self.timer.setInterval(2000)
        self.timer.timeout.connect(self.update_label)
        self.timer.start()
        
        # 启动事件循环,持续处理事件直到停止
        loop = QEventLoop()
        while self.is_running:
            loop.processEvents()
        
        self.timer.stop()

    def update_label(self):
        provider = configfile.provider
        number = str(nmbr.latest_numer(provider))
        self.update_progress.latest_number.emit(number)
        print("update label started")

# MainWindow部分与原代码一致,注意需添加停止Updater的逻辑

额外提示

如果获取latest_numer的操作不耗时,完全可以直接在主线程用QTimer,无需额外开线程:

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        # ... 其他初始化代码 ...
        
        self.timer = QtCore.QTimer()
        self.timer.setInterval(2000)
        self.timer.timeout.connect(self.update_number_directly)
        self.timer.start()

    def update_number_directly(self):
        provider = configfile.provider
        number = str(nmbr.latest_numer(provider))
        self.number.setText(f"Current block: {number}")

内容的提问来源于stack exchange,提问作者Marcello De Paola

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 03:45:44