使用Kivy.clock开发应用内Tracker模块秒表时触发Attribute Error问题求助
解决Tracker模块的AttributeError及定时器逻辑问题
首先来说你遇到的AttributeError:你在代码里用self.root.ids去访问start_stop_btn、sec_ones这些控件,但这些控件是定义在Tracker这个Screen内部的,self.root指向的是你的App根容器(一般是ScreenManager),它根本没有这些id,所以应该改成self.ids来访问当前Screen内的控件——这就是触发错误的核心原因。
除了这个错误,你的定时器逻辑还有两个致命问题,会导致程序异常甚至卡死:
- 每次点击Start按钮都会重复调用
Clock.schedule_interval,这会让多个定时器同时运行,时间会被无意义地加速; add_time里的while self.start循环会阻塞Kivy的主线程,Kivy是单线程框架,这个循环会让UI完全无法更新,也无法响应其他操作。
下面是修复后的完整代码:
修复后的Python代码
from kivy.uix.screenmanager import Screen from kivy.clock import Clock class Tracker(Screen): time = 0 start = False timer_event = None # 用来保存定时器事件,方便后续取消 def start_stop(self): self.start = not self.start self.ids.start_stop_btn.text = 'Stop' if self.start else 'Start' if self.start: # 仅在启动时调度定时器,每秒执行一次add_time self.timer_event = Clock.schedule_interval(self.add_time, 1) else: # 停止时取消定时器,避免重复调度 if self.timer_event: self.timer_event.cancel() self.timer_event = None def add_time(self, *args): # 因为定时器每秒自动调用一次,所以不需要while循环,每次执行一次时间递增逻辑即可 sec_ones = int(self.ids.sec_ones.text) + 1 sec_tens = int(self.ids.sec_tens.text) minute_ones = int(self.ids.minute_ones.text) minute_tens = int(self.ids.minute_tens.text) if sec_ones == 10: sec_ones = 0 sec_tens += 1 if sec_tens == 6: sec_tens = 0 minute_ones += 1 if minute_ones == 10: minute_ones = 0 minute_tens += 1 # 更新UI显示 self.ids.sec_ones.text = str(sec_ones) self.ids.sec_tens.text = str(sec_tens) self.ids.minute_ones.text = str(minute_ones) self.ids.minute_tens.text = str(minute_tens) self.time += 1 print(f"总时长:{self.time}秒")
对应的kv代码(无需修改)
<Tracker>: name: "Tracker" Label: text: "Timer: " font_size: 50 pos_hint: {'x': 0.1, 'top': 1} size_hint: 0.2, 0.2 Label: id: minute_tens text: '0' pos_hint: {'x': 0.36, 'top': 0.99} font_size: 40 size_hint: 0.1, 0.2 canvas.before: Color: rgba: (0.349, 0.349, 0.349, 1) Rectangle: pos: self.pos size: self.size Label: id: minute_ones text: '0' pos_hint: {'x': 0.47, 'top': 0.99} font_size: 40 size_hint: 0.1, 0.2 canvas.before: Color: rgba: (0.349, 0.349, 0.349, 1) Rectangle: pos: self.pos size: self.size Label: text: ':' pos_hint: {'x': 0.59, 'top': 0.99} font_size: 40 size_hint: 0.05, 0.2 Label: id: sec_tens text: '0' pos_hint: {'x': 0.65, 'top': 0.99} font_size: 40 size_hint: 0.1, 0.2 canvas.before: Color: rgba: (0.349, 0.349, 0.349, 1) Rectangle: pos: self.pos size: self.size Label: id: sec_ones text: '0' pos_hint: {'x': 0.76, 'top': 0.99} font_size: 40 size_hint: 0.1, 0.2 canvas.before: Color: rgba: (0.349, 0.349, 0.349, 1) Rectangle: pos: self.pos size: self.size Button: id: start_stop_btn text: 'Start' pos_hint: {'x': 0.6, 'top': 0.77} size_hint: 0.1, 0.06 on_release: root.start_stop() SmoothButton: text: "Back" pos_hint: {'x': 0.8, 'top': 0.15} size_hint: 0.15, 0.05 on_release: app.root.current = "HomePage" root.manager.transition.direction = "right"
修复要点说明:
- 把所有
self.root.ids替换成self.ids,正确访问当前Screen内的控件; - 新增
timer_event变量保存定时器事件,点击Stop时取消调度,避免重复启动多个定时器; - 移除
add_time里的while循环,利用Clock.schedule_interval的特性每秒自动执行一次时间递增逻辑; - 重构时间递增的逻辑,用变量先存储数值,计算完成后再统一更新UI,代码更清晰易维护。
这样修改后,点击Start按钮就不会再触发AttributeError,定时器也能正常工作,UI也不会卡死了。
内容的提问来源于stack exchange,提问作者Jayanti
相关产品推荐
相关产品推荐

