Python Kivy:循环创建按钮后如何正确记录点击的按钮实例?
解决Kivy循环创建按钮时
self.i值无法保留的问题 这个问题我太熟了!你遇到的是Python里闭包延迟绑定的经典坑——循环里的self.i在按钮点击触发add方法时才会被读取,这时候循环早就跑完了,self.i自然停在最后一个值(也就是2)。咱们一步步来解决,顺便回答你关于条件判断存储的疑问:
一、最简洁有效的解决方案:直接从按钮实例获取信息
绑定的add方法里的第一个参数(你写的_)其实就是被点击的按钮对象本身!完全不需要依赖self.i,直接从这个参数里拿id或自定义属性就行:
修改你的代码如下:
class InfoPage(GridLayout): def __init__(self, **kwargs): super(InfoPage, self).__init__(**kwargs) self.cols = 1 self.peers = ["ishika", "nate", "nf"] # 建议不要修改原peers列表,直接创建按钮变量 for i in range(3): btn = Button(text=self.peers[i], id=str(i)) self.add_widget(btn) btn.bind(on_press=self.add) def add(self, button): # 直接从点击的按钮实例取id id_of_button_pressed = button.id print(f"被点击的按钮ID:{id_of_button_pressed}")
这样不管循环怎么运行,每个按钮点击时都会把自己的实例传递给add方法,直接取自己的id,完美规避self.i的问题。
二、如果一定要保留self.i的关联:用默认参数捕获当前值
如果业务逻辑需要用到循环时的i值,可以在绑定事件时用lambda的默认参数,把当前循环的i值固定住(默认参数会在lambda定义时就存储当前值,而不是调用时再读取):
class InfoPage(GridLayout): def __init__(self, **kwargs): super(InfoPage, self).__init__(**kwargs) self.cols = 1 self.peers = ["ishika", "nate", "nf"] for i in range(3): btn = Button(text=self.peers[i], id=str(i)) self.add_widget(btn) # 用默认参数current_i=i捕获当前循环的i值 btn.bind(on_press=lambda _, current_i=i: self.add(_, current_i)) def add(self, _, current_i): id_of_button_pressed = self.peers[current_i] print(f"当前i值:{current_i},对应按钮文本:{id_of_button_pressed}")
三、关于你问的「用条件判断存储self.i」
其实没必要额外加条件判断——因为on_press事件本身就是只有按钮被点击时才会触发的。不过如果想显式存储每个按钮对应的i值,可以给按钮添加自定义属性:
class InfoPage(GridLayout): def __init__(self, **kwargs): super(InfoPage, self).__init__(**kwargs) self.cols = 1 self.peers = ["ishika", "nate", "nf"] self.stored_i = None # 用于存储点击的i值 for i in range(3): btn = Button(text=self.peers[i], id=str(i)) btn.current_i = i # 给按钮加自定义属性,存当前循环的i self.add_widget(btn) btn.bind(on_press=self.add) def add(self, button): # 点击时把对应i值存到self.stored_i self.stored_i = button.current_i print(f"存储的i值:{self.stored_i},按钮ID:{button.id}")
这样就实现了“点击按钮时将对应i值存储到其他变量”的需求。
内容的提问来源于stack exchange,提问作者ishika
相关产品推荐
相关产品推荐

