Kivy与KivyMD向列表添加组件报AttributeError修复方案
报错根因
Kivy/KivyMD触发AttributeError: 'super' object has no attribute '__getattr__',本质是调用ids取控件时,目标id不在当前作用域的ids映射表中,常见触发场景:
- 操作ids的时机过早,kv布局文件还没完成渲染挂载,ids字典还未生成对应键值
- id拼写错误、大小写不匹配
- 目标控件定义在嵌套子容器(比如Screen、弹窗、自定义组件)的kv作用域下,直接从App根节点的ids中查找无法命中
修复方案
1. 调整操作时机
不要在__init__、build()方法执行阶段直接操作ids,这一阶段kv树还未完成挂载,必须将批量添加条目的逻辑挪到on_start生命周期钩子中执行,该钩子触发时整个kv布局已经完全加载,ids映射表可用。
错误示例(禁止写法):
class MainApp(MDApp): def build(self): self.theme_cls.primary_palette = "Blue" # 此处kv尚未加载完成,ids为空,调用必报错 for i in range(10): self.root.ids.List_setting.add_widget(OneLineListItem(text=f"条目{i}")) return Builder.load_file("kv_main.kv")
正确写法:
class MainApp(MDApp): def build(self): self.theme_cls.primary_palette = "Blue" return Builder.load_file("kv_main.kv") def on_start(self): # 调试阶段可先打印所有可用id,确认目标id存在 # print(self.root.ids.keys()) setting_list = self.root.ids.List_setting for i in range(10): setting_list.add_widget( OneLineListItem( text=f"设置项 {i+1}", on_press=lambda x, idx=i: self.handle_item_press(idx) ) ) def handle_item_press(self, item_index): print(f"触发第{item_index+1}项的点击事件")
2. 修正id查找路径
Kivy的ids是按kv根节点做作用域隔离的,如果你的List_setting定义在ScreenManager下属的Screen、自定义弹窗、自定义组件内部,不能直接从self.root.ids查找,需要先定位到持有该id的直接父容器:
示例:如果List_setting写在name为
setting_screen的Screen下,查找方式如下
# 先拿到ScreenManager实例,再取对应Screen,最后拿目标id setting_list = self.root.ids.screen_manager.get_screen("setting_screen").ids.List_setting
3. 基础排查清单
- 核对kv文件中目标控件的id拼写,和代码中调用的
List_setting大小写完全一致,Kivy的id大小写敏感 - 检查
List_setting是否写在<自定义组件名>的kv模板规则中,模板内定义的id不会出现在实例的ids映射表中 - 动态加载kv的场景下,要等Builder返回的根节点挂载到窗口后再操作ids
代码优化建议
- 列表条目超过20个时,不要直接循环
add_widget堆叠MDList项,改用RecycleView实现列表,滚动流畅度会提升数倍,避免内存占用过高 - 统一id命名规范,使用小写下划线格式(比如
list_setting),和Kivy官方编码风格保持一致,降低拼写错误概率 - 操作ids前增加存在性判断,减少调试阶段的报错中断:
if "List_setting" in self.root.ids: # 执行添加逻辑 else: print("当前根节点可用id:", list(self.root.ids.keys()))
- 列表项的事件回调单独抽成类方法,不要在循环内写过长的匿名函数,降低后期维护成本
内容的提问来源于stack exchange,提问作者Yellow_Ananas
相关产品推荐
相关产品推荐

