Kivy单按钮秒表:实现长按重置遇AttributeError问题求助
Kivy秒表单按钮实现启停+长按重置解决方案
问题原因
Kivy标准Button组件未内置on_long_press事件,直接绑定该事件会触发AttributeError: long_press。要实现长按功能,需通过自定义逻辑结合Clock检测触摸时长,区分短按与长按操作。
解决方案:自定义长按按钮类
推荐继承Button实现支持长按事件的自定义按钮,组件可复用且逻辑清晰。
修改后的Python代码
from kivy.app import App from kivy.uix.screenmanager import ScreenManager, Screen from kivy.clock import Clock from kivy.lang import Builder from kivy.uix.button import Button from kivy.properties import NumericProperty, ObjectProperty class LongPressButton(Button): # 长按阈值(秒),可在kv中自定义 long_press_threshold = NumericProperty(2) # 长按触发事件 on_long_press = ObjectProperty(None) def __init__(self, **kwargs): super().__init__(**kwargs) self.touch_start_time = None self.long_press_schedule = None def on_touch_down(self, touch): # 检测触摸是否落在按钮范围内 if self.collide_point(*touch.pos) and touch.is_touch: self.touch_start_time = Clock.get_time() # 计划长按触发事件 self.long_press_schedule = Clock.schedule_once(self._trigger_long_press, self.long_press_threshold) return super().on_touch_down(touch) def on_touch_up(self, touch): if self.collide_point(*touch.pos) and touch.is_touch: if self.touch_start_time is not None: touch_duration = Clock.get_time() - self.touch_start_time # 触摸时长小于阈值,判定为短按,触发原on_press事件 if touch_duration < self.long_press_threshold: self.dispatch('on_press') # 取消未触发的长按计划 if self.long_press_schedule is not None: Clock.unschedule(self.long_press_schedule) self.touch_start_time = None self.long_press_schedule = None return super().on_touch_up(touch) def _trigger_long_press(self, dt): # 触发长按事件 if self.on_long_press: self.on_long_press() self.touch_start_time = None self.long_press_schedule = None class HomeScreen(Screen): elapsed_time = 0 def update_time(self, dt): self.elapsed_time += dt mins, secs = divmod(round(self.elapsed_time), 60) self.ids.stopwatch_display.text = '{:02d}:{:02d}'.format(mins, secs) def start_stop(self): if self.ids.stopwatch_display.start_or_end == 'Start': Clock.schedule_interval(self.update_time, 0.1) self.ids.stopwatch_display.start_or_end = 'Stop' else: Clock.unschedule(self.update_time) self.ids.stopwatch_display.start_or_end = 'Start' def reset_time(self): self.elapsed_time = 0 self.ids.stopwatch_display.text = '00:00' Clock.unschedule(self.update_time) self.ids.stopwatch_display.start_or_end = 'Start' class TheApp(App): def build(self): sm = ScreenManager() sm.add_widget(HomeScreen(name='home_screen')) return sm def main(): Builder.load_file('menu.kv') app = TheApp() app.run() if __name__ == '__main__': main()
修改后的kv代码(menu.kv)
<HomeScreen>: LongPressButton: id: stopwatch_display text: '00:00' start_or_end: 'Start' # 短按触发启停 on_press: root.start_stop() # 长按触发重置 on_long_press: root.reset_time() # 自定义长按阈值(可选,默认2秒) long_press_threshold: 2 # 布局属性,居中显示 size_hint: 0.8, 0.2 pos_hint: {'center_x': 0.5, 'center_y': 0.5}
关键说明
- 自定义按钮逻辑:通过
on_touch_down记录触摸开始时间,用Clock.schedule_once计划长按触发;on_touch_up时计算触摸时长,区分短按/长按操作。 - 事件绑定:短按仍使用原
on_press绑定启停逻辑,长按通过自定义的on_long_press绑定重置逻辑。 - 移除冗余组件:原
reset_button可直接删除,所有功能整合到单个按钮中,优化触控体验。
内容的提问来源于stack exchange,提问作者Max Davies
相关产品推荐
相关产品推荐

