Tkinter中update()/update_idletasks()调用频次递增问题求助
问题分析与解决方案
你的问题核心在于重复注册定时任务,同时错误地混合使用了阻塞式while循环和Tkinter的after机制,导致up()函数被多次触发,进而update()的调用频次不断递增,最终造成资源占用上升。
具体原因拆解
- 点击"Run"按钮触发
Running()方法后,里面的while self.s循环会持续调用self.up(); - 而
self.up()中又通过self.master.after(100, self.up)注册了新的定时任务——每调用一次up()就多一个定时触发它的任务; - 随着
while循环执行,定时任务会越积越多,up()被调用的次数自然逐次递增,print("update")的输出也就越来越多。 - 另外,Tkinter的
mainloop()本身就是事件循环,手动调用update()通常是不必要的,反而会干扰正常的事件处理流程。
可行解决方案
我们需要重构代码,用Tkinter原生的after机制替代阻塞式while循环,让电机运转逻辑融入Tkinter的事件循环,避免重复注册任务:
修改后的代码示例
import tkinter as tk import smbus class GUI(object): def __init__(self, master): self.globalvar() self.bus = smbus.SMBus(1) self.master = master self.s = False # 控制电机运行的标志位 self.motor_task_id = None # 存储定时任务ID,用于取消任务 # 加载GUI self.loadGUI() def Running(self): if not self.s: self.s = True # 启动电机运转的循环任务 self._run_motor() def Stop(self): self.s = False # 如果有正在运行的定时任务,取消它 if self.motor_task_id: self.master.after_cancel(self.motor_task_id) self.motor_task_id = None print("Stop") def _run_motor(self): if self.s: # 执行电机运转逻辑 movethemotor() # 注册下一次运转的任务,避免重复注册 self.motor_task_id = self.master.after(100, self._run_motor) # 这里不需要手动调用update(),mainloop会处理事件 def up(self): # 保留你原本up函数的其他逻辑(比如更新UI控件状态) # 移除手动的update()调用 pass if __name__ == "__main__": root = tk.Tk() root.title("MLCT GUI") rpi = GUI(root) root.geometry('1050x530') root.resizable(False, False) root.mainloop()
关键改动说明
- 移除了
up()中的update()和after(100, self.up),将电机运转的循环逻辑单独放到_run_motor()方法中; - 用
self.motor_task_id存储定时任务的ID,点击"Stop"时可以通过after_cancel()取消未执行的任务; Running()方法不再使用阻塞式while循环,而是通过after机制递归调用_run_motor(),完全融入Tkinter的事件循环,避免阻塞UI响应;- 不再手动调用
update(),依赖mainloop()处理所有事件(包括UI更新、按钮点击等)。
如果你原本的up()方法是用来更新UI控件状态的,可以把这部分逻辑合并到_run_motor()中,或者单独用另一个定时任务处理,但要确保只注册一次定时任务,避免重复触发。
内容的提问来源于stack exchange,提问作者fausto tromba
相关产品推荐
相关产品推荐

