Kivy中无法通过id修改Rectangle的source属性的报错求助
问题根因与修复方案
触发报错的核心原因
- 无效控件实例化:
swap()方法中执行Picture().change()时,会生成一个未挂载到界面树的空白Picture对象,该对象未加载对应的kv配置,不存在任何已绑定的组件引用,访问self.ids.rec时必然触发属性不存在的报错。原代码在TileWidget.__init__中已经创建并添加了一个实际展示的Picture实例,但后续逻辑未引用该实例,反而新建了无效对象。 - canvas指令的id绑定规则:Kivy的
ids字典仅自动收集kv规则中定义的、属于控件子节点的UI组件id,直接写在canvas块内的图形指令(如Rectangle)的id,不会自动加入所属控件的ids字典,即便使用正确的已挂载实例,直接访问self.ids.rec也会触发键不存在的错误。
具体修复步骤
- 用属性绑定替代id访问
在Picture类中定义自定义属性,直接将Rectangle的图片源与该属性绑定,修改属性值时自动触发画布重绘,无需手动访问canvas内的节点。 - 修正实例引用逻辑
将TileWidget.__init__中创建的Picture实例存为类成员,swap()方法直接调用该已挂载到界面的实例的切换方法,不再新建无效对象。 - 优化计数逻辑
将原全局计数变量x改为Picture类的内部成员,避免全局变量带来的状态混乱。
修正后的完整代码
Python 代码
from kivy.app import App from kivy.uix.floatlayout import FloatLayout from kivy.properties import StringProperty class Picture(FloatLayout): # 绑定图片源属性,初始值与原配置一致 source = StringProperty("images.jpg") swap_count = 0 # 记录切换次数的内部变量 def change(self): self.swap_count += 1 if self.swap_count % 2 == 0: self.source = "download.jpg" print("aaaa") else: self.source = "images.jpg" print("bbbbb") class TileWidget(FloatLayout): def __init__(self, **kwargs): super(TileWidget, self).__init__(**kwargs) # 保存实际显示的Picture实例引用 self.pic_widget = Picture() self.add_widget(self.pic_widget) def swap(self): # 直接调用已挂载实例的切换方法 self.pic_widget.change() class langApp(App): def build(self): return TileWidget() if __name__ == '__main__': langApp().run()
KV 配置文件
#:kivy 1.11.1 <TileWidget>: FloatLayout: pos: 0,0 size: root.width,root.height Button: text: 'Last' pos_hint: {'x':.25,'y':.1} size_hint: .1,.1 Button: text: 'Stop' pos_hint: {'x':.45,'y':.1} size_hint: .1,.1 Button: on_press: root.swap() text: 'Next' pos_hint: {'x':.65,'y':.1} size_hint: .1,.1 <Picture>: pos_hint: {'x':.25,'y':.4} canvas: Rectangle: size: self.size[0]*0.5,self.size[1]*0.5 pos: self.pos[0],self.pos[1] # 直接绑定Picture类的source属性,无需依赖id source: root.source
内容的提问来源于stack exchange,提问作者Leon Kardaš
相关产品推荐
相关产品推荐

