如何在Python代码中动态修改Kivy控件on_release属性实现屏幕切换
问题原因
- 你直接为
on_release赋值self.switch_to(Screen(name='av'))时,代码会立即执行切换逻辑,最终是把方法的返回值(默认None)绑定给了点击事件,而非将切换逻辑作为可调用对象在点击时触发。 - 手动创建的
Screen(name='av')是全新的独立实例,和你提前加到ScreenManager里的AVCard实例无关联,无法完成正确跳转。 - 存在几处可导致运行错误的笔误:属性声明
NumbericProperty应为NumericProperty;Python中定义的AVCard类与KV中声明的<AVScreen>命名不匹配;UpdateVariables继承了Screen但你实际是将其作为HomeScreen的子组件使用,嵌套Screen会导致布局和逻辑异常。
修复方案
基础实现(按你原有动态绑定的逻辑修改)
第一步:调整UpdateVariables类的继承和基础逻辑
from kivy.uix.widget import Widget from kivy.uix.screenmanager import FadeTransition class UpdateVariables(Widget): # 改继承Widget,不要继承Screen currentpr = ObjectProperty(None) currentcardpr = ObjectProperty(None) minute_in_day = NumericProperty() # 修正拼写错误 def __init__(self,**kwargs): super(UpdateVariables,self).__init__(**kwargs) Clock.schedule_interval(self.update_time, 1) self.now = datetime.now() # 新增通用切换逻辑,统一处理跳转和过渡效果 def switch_screen(self, screen_name): # 获取顶层ScreenManager实例 screen_manager = self.parent.manager screen_manager.transition = FadeTransition(duration=0.1) screen_manager.current = screen_name
第二步:修改动态绑定逻辑
绑定点击事件时用lambda包装可调用对象,避免立即执行,同时每次绑定前清空旧绑定防止重复触发:
def update_time(self, dt): self.timelablepr.text = '[size=20][b]' + time.strftime('%H:%M:%S') self.hour = int(time.strftime("%H")) self.minute = int(time.strftime("%M")) self.minute_in_day = self.hour*60 + self.minute # 清空之前的绑定 if self.currentcardpr.on_release: self.currentcardpr.unbind(on_release=self.currentcardpr.on_release) if self.minute_in_day in range(100, 200): self.currentpr.text = "this is AV" # lambda加*args适配on_release自动传入的控件参数 self.currentcardpr.on_release = lambda *args: self.switch_screen('av') elif self.minute_in_day in range(200, 300): self.currentpr.text = "..." self.currentcardpr.on_release = lambda *args: self.switch_screen('你的其他屏幕名称')
优化实现(更稳定,避免频繁绑定/解绑)
不用动态修改绑定逻辑,只需将目标跳转屏幕存为属性,固定绑定一个跳转方法即可,性能和稳定性更好:
class UpdateVariables(Widget): currentpr = ObjectProperty(None) currentcardpr = ObjectProperty(None) minute_in_day = NumericProperty() target_screen = StringProperty('av') # 存储当前要跳转的屏幕名 def __init__(self,**kwargs): super(UpdateVariables,self).__init__(**kwargs) Clock.schedule_interval(self.update_time, 1) self.now = datetime.now() # 仅绑定一次点击事件 self.currentcardpr.bind(on_release=self.jump_to_target) def jump_to_target(self, *args): screen_manager = self.parent.manager screen_manager.transition = FadeTransition(duration=0.1) screen_manager.current = self.target_screen def update_time(self, dt): self.timelablepr.text = '[size=20][b]' + time.strftime('%H:%M:%S') self.hour = int(time.strftime("%H")) self.minute = int(time.strftime("%M")) self.minute_in_day = self.hour*60 + self.minute if self.minute_in_day in range(100, 200): self.currentpr.text = "this is AV" self.target_screen = 'av' # 仅修改目标屏幕属性 elif self.minute_in_day in range(200, 300): self.currentpr.text = "..." self.target_screen = '你的其他屏幕名称'
内容的提问来源于stack exchange,提问作者SnowyField
相关产品推荐
相关产品推荐

