Kivy自定义组件中Spinner调用add_key报错,Checkbox却正常
Kivy中Spinner触发
add_key报错AttributeError: 'NoneType' object has no attribute 'add_key'的原因与解决方法 问题原因
- 你在
MainScreen的__init__方法中直接设置Spinner的text属性,这会立刻触发Spinner的on_text事件。 - 此时
MainScreen刚被实例化,还未被赋值给app.root(app.root要在App.build()返回后才会被系统设置),所以on_text绑定代码里的app.root是None,调用add_key自然抛出属性错误。 - 而Checkbox的
on_active事件是用户手动点击时才触发,此时App已完成初始化,app.root已经指向MainScreen实例,因此能正常调用add_key。
解决方案
方法1:延迟初始化Spinner属性
借助Clock.schedule_once延迟执行Spinner的属性设置,确保app.root已存在:
from kivy.app import App from kivy.uix.screenmanager import Screen from kivy.lang import Builder from kivy.clock import Clock selection = {} pizza = ["margarita", "vegetarian", "american", "3 cheeses"] KV=""" <Selection@BoxLayout> orientation: "horizontal" label_txt: "" key_name: "" Label: text: root.label_txt Spinner: id: spin_id text: "" on_text: app.root.add_key(root.key_name, self.text) <Radio_op@BoxLayout> orientation: "horizontal" op: "" label_op: "" Label: text: root.label_op CheckBox: group:"topping" on_active: app.root.add_key("topping", root.op) <MainScreen> BoxLayout: orientation: "vertical" Selection: id: pizza_sel label_txt: "pizza" key_name: "pizza" Label: text: "Choose topping:" BoxLayout: orientation: "horizontal" Radio_op: label_op:"cream" op: "cream" Radio_op: label_op:"cheese" op: "cheese" Radio_op: label_op:"tomatoes" op: "tomatoes" BoxLayout: Label: id: pizza_lbl Label: id: topping_lbl """ class MainScreen(Screen): def __init__(self, **kwargs): super(MainScreen, self).__init__(**kwargs) # 延迟执行Spinner初始化 Clock.schedule_once(self.init_spinner) def init_spinner(self, dt): self.ids.pizza_sel.ids.spin_id.text = pizza[0] self.ids.pizza_sel.ids.spin_id.values = pizza def add_key(self, name, text): selection[name] = text # 判空避免键不存在报错 if "pizza" in selection: self.ids.pizza_lbl.text = selection["pizza"] if "topping" in selection: self.ids.topping_lbl.text = selection["topping"] Builder.load_string(KV) class MyApp(App): def build(self): return MainScreen() if __name__ == '__main__': MyApp().run()
方法2:在事件绑定中增加判空逻辑
修改KV中Spinner的on_text绑定,先检查app.root是否有效再调用方法:
Spinner: id: spin_id text: "" on_text: if app.root: app.root.add_key(root.key_name, self.text)
同时建议在add_key方法中对selection的键做判空处理,避免因键不存在导致额外报错。
方法3:直接在KV中完成Spinner初始化
将Spinner的初始值和选项直接通过KV传递,避免在Python代码中触发on_text事件:
修改KV部分:
<Selection@BoxLayout> orientation: "horizontal" label_txt: "" key_name: "" pizza_options: [] Label: text: root.label_txt Spinner: id: spin_id text: root.pizza_options[0] if root.pizza_options else "" values: root.pizza_options on_text: app.root.add_key(root.key_name, self.text) <MainScreen> BoxLayout: orientation: "vertical" Selection: id: pizza_sel label_txt: "pizza" key_name: "pizza" pizza_options: pizza # 其余部分不变
同时删除MainScreen的__init__中设置Spinner属性的代码,这样初始化阶段不会触发on_text事件。
内容的提问来源于stack exchange,提问作者Flob74
相关产品推荐
相关产品推荐

