PySide2中QTimer绑定lambda函数复用旧数据问题排查
QTimer绑定Lambda传递数据时旧数据残留问题
我使用Python 3.8搭配PySide2开发GUI项目,在QThread中执行后台任务,其中包含一个QTimer成员对象,需要周期性调用函数并每次传入不同数据。因需在特定场景下停止/重置定时器,未使用QTimer.singleShot静态方法。
目标函数执行完成后,会调用另一函数向定时器传入新数据并重新启动。我通过timer.timeout.connect(lambda: function_name(data))绑定函数,且在传入新数据前会停止定时器并断开旧槽函数,但第二次运行时目标函数仍使用旧数据。
复现代码
from PySide2.QtCore import QTimer from PySide2 import QtWidgets import time import logging logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) FORMAT = "[%(asctime)s] %(funcName)s: %(message)s" logging.basicConfig(format=FORMAT) class QtTest(QtWidgets.QWidget): def __init__(self): super(QtTest, self).__init__() logger.info("Class initialized") self.timer = QTimer() self.timer.setSingleShot(True) self.timer.setInterval(1000) self.timer.timeout.connect(lambda: self.target_func(0)) self.timer.start() def target_func(self, data): logger.info("Target function called with data: {}".format(data)) time.sleep(1.5) if self.timer.isActive(): logger.info("Timer reset") self.timer.stop() self.timer.timeout.disconnect() self.func_done(data) def func_done(self, data): logger.info("Tasks completed for data: {}".format(data)) if data == 0: logger.info("Setting next timer with data 1") #I have tried the following as well #self.timer.timeout.disconnect() #self.timer.stop() self.timer.setInterval(1000) self.timer.timeout.connect(lambda: self.target_func(1)) self.timer.start() def init_app(): app = QtWidgets.QApplication([]) gui = QtTest() gui.show() app.exec_() if __name__ == "__main__": print("QT app running") init_app() test = QtTest()
测试输出
QT app running [2024-07-30 22:44:53,204] __init__: Class initialized [2024-07-30 22:44:54,255] target_func: Target function called with data: 0 [2024-07-30 22:44:55,757] func_done: Tasks completed for data: 0 [2024-07-30 22:44:55,757] func_done: Setting next timer with data 1 [2024-07-30 22:44:56,808] target_func: Target function called with data: 0 [2024-07-30 22:44:58,309] func_done: Tasks completed for data: 0 [2024-07-30 22:44:58,309] func_done: Setting next timer with data 1 [2024-07-30 22:44:58,309] target_func: Target function called with data: 1 [2024-07-30 22:44:59,810] target_func: Timer reset [2024-07-30 22:44:59,811] func_done: Tasks completed for data: 1
问题根源
因为设置了setSingleShot(True),定时器触发timeout信号后会自动变为非活跃状态,导致target_func中的if self.timer.isActive()条件不成立,没有断开旧的槽函数。后续绑定新的lambda时,旧的槽函数依然存在,定时器触发时会同时执行新旧两个lambda,因此先输出旧数据0,再输出新数据1。
修复方案
每次绑定新的槽函数前,强制断开timeout信号的所有连接,不需要依赖isActive()判断:
修改后的代码
from PySide2.QtCore import QTimer from PySide2 import QtWidgets import time import logging logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) FORMAT = "[%(asctime)s] %(funcName)s: %(message)s" logging.basicConfig(format=FORMAT) class QtTest(QtWidgets.QWidget): def __init__(self): super(QtTest, self).__init__() logger.info("Class initialized") self.timer = QTimer() self.timer.setSingleShot(True) self.timer.setInterval(1000) self.timer.timeout.connect(lambda: self.target_func(0)) self.timer.start() def target_func(self, data): logger.info("Target function called with data: {}".format(data)) time.sleep(1.5) # 移除isActive判断,直接断开连接(即使定时器已非活跃) self.timer.stop() self.timer.timeout.disconnect() self.func_done(data) def func_done(self, data): logger.info("Tasks completed for data: {}".format(data)) if data == 0: logger.info("Setting next timer with data 1") self.timer.setInterval(1000) self.timer.timeout.connect(lambda: self.target_func(1)) self.timer.start() def init_app(): app = QtWidgets.QApplication([]) gui = QtTest() gui.show() app.exec_() if __name__ == "__main__": print("QT app running") init_app() test = QtTest()
预期输出
QT app running [2024-XX-XX XX:XX:XX,XXX] __init__: Class initialized [2024-XX-XX XX:XX:XX,XXX] target_func: Target function called with data: 0 [2024-XX-XX XX:XX:XX,XXX] func_done: Tasks completed for data: 0 [2024-XX-XX XX:XX:XX,XXX] func_done: Setting next timer with data 1 [2024-XX-XX XX:XX:XX,XXX] target_func: Target function called with data: 1 [2024-XX-XX XX:XX:XX,XXX] func_done: Tasks completed for data: 1
内容的提问来源于stack exchange,提问作者soslearn
相关产品推荐
相关产品推荐

