Kivy嵌套TaskTemplate时报AttributeError属性不存在错误
问题描述
我定义了包含Button、TextInput等控件的TaskTemplate组件,核心代码片段如下:
class TaskTemplate(BoxLayout, Button): task_name = StringProperty() def __init__(self): super(TaskTemplate, self).__init__() self.update_state = 'down'
对应的kv规则:
<TaskTemplate>: RelativeLayout: CheckBox: state: root.update_state
- 当
TaskTemplate作为应用根类使用时,程序运行完全正常,可以通过update_state参数修改CheckBox的选中状态。 - 但将
TaskTemplate按如下结构添加到MainScreen中时,程序抛出无限循环报错:
MainScreen: <MainScreen>: BoxLayout: ScrollView: GridLayout: id: here_add_task_template
报错核心信息为AttributeError: 'TaskTemplate' object has no attribute 'update_state',完整报错栈如下:
Traceback (most recent call last): File "C:\Users\barbu\OneDrive\Desktop\Final App 2\venv\lib\site-packages\kivy\lang\builder.py", line 240, in create_handler return eval(value, idmap), bound_list File "C:\Users\barbu\OneDrive\Desktop\Final App 2\middleScreen.kv", line 122, in <module> state: root.update_state File "kivy\weakproxy.pyx", line 32, in kivy.weakproxy.WeakProxy.__getattr__ AttributeError: 'TaskTemplate' object has no attribute 'update_state' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\Users\barbu\OneDrive\Desktop\Final App 2\venv\lib\site-packages\kivy\lang\builder.py", line 694, in _apply_rule value, bound = create_handler( File "C:\Users\barbu\OneDrive\Desktop\Final App 2\venv\lib\site-packages\kivy\lang\builder.py", line 243, in create_handler raise BuilderException(rule.ctx, rule.line, kivy.lang.builder.BuilderException: Parser: File "C:\Users\barbu\OneDrive\Desktop\Final App 2\middleScreen.kv", line 122: ... 120:# root.update_index() 121:# root.save_in_json(self) >> 122: state: root.update_state 123: 124: Button: ... AttributeError: 'TaskTemplate' object has no attribute 'update_state' File "C:\Users\barbu\OneDrive\Desktop\Final App 2\venv\lib\site-packages\kivy\lang\builder.py", line 240, in create_handler return eval(value, idmap), bound_list File "C:\Users\barbu\OneDrive\Desktop\Final App 2\middleScreen.kv", line 122, in <module> state: root.update_state File "kivy\weakproxy.pyx", line 32, in kivy.weakproxy.WeakProxy.__getattr__ During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\Users\barbu\OneDrive\Desktop\Final App 2\main.py", line 246, in <module> MainApp().run() File "C:\Users\barbu\OneDrive\Desktop\Final App 2\venv\lib\site-packages\kivy\app.py", line 955, in run runTouchApp() File "C:\Users\barbu\OneDrive\Desktop\Final App 2\venv\lib\site-packages\kivy\base.py", line 574, in runTouchApp EventLoop.mainloop() File "C:\Users\barbu\OneDrive\Desktop\Final App 2\venv\lib\site-packages\kivy\base.py", line 341, in mainloop self.window.mainloop() File "C:\Users\barbu\OneDrive\Desktop\Final App 2\venv\lib\site-packages\kivy\core\window\window_sdl2.py", line 757, in mainloop if self.dispatch('on_key_down', key, File "kivy\_event.pyx", line 727, in kivy._event.EventDispatcher.dispatch
问题原因
报错由两个核心问题触发:
- 继承顺序错误:Kivy控件多继承时,事件交互类需要放在布局类前面,否则会打乱MRO初始化顺序,导致属性、事件注册异常。你写的
class TaskTemplate(BoxLayout, Button)顺序完全写反。 - 属性定义方式错误:
update_state是你在__init__里动态绑定的普通实例属性,不是Kivy原生的Property类型。组件作为根节点时,kv规则解析时机刚好在__init__执行完成后,所以能找到属性;但组件作为子组件嵌套加载时,kv规则解析会发生在__init__属性赋值之前,就会触发属性找不到的错误,再叠加Kivy的规则自动重试机制,就会出现无限循环抛错的现象。
修复方法
按如下步骤修改即可解决问题:
- 调整类继承顺序,把交互控件类
Button放在布局类BoxLayout前面 - 把
update_state定义为类级别的StringProperty(CheckBox的state接受字符串值,对应'normal'/'down'两个状态),直接给默认值,不要在__init__里动态赋值普通属性 - 给
__init__方法添加**kwargs参数,调用父类初始化时把参数透传,避免Kivy控件初始化时丢失必要参数
修改后的Python代码参考:
from kivy.properties import StringProperty from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button class TaskTemplate(Button, BoxLayout): task_name = StringProperty() update_state = StringProperty('down') def __init__(self, **kwargs): super(TaskTemplate, self).__init__(**kwargs)
修改后组件无论作为根节点,还是动态添加到MainScreen的GridLayout中,都能正常加载运行,不会再抛出属性不存在的错误。
内容的提问来源于stack exchange,提问作者Adrian Barbu
相关产品推荐
相关产品推荐

