使用MDDropdownMenu实现递归动态选单时遇到的问题(续)
看起来你遇到的AttributeError: 'super' object has no attribute '__getattr__'主要是因为在App的__init__方法过早访问kv部件的ids,而且你的逻辑位置不符合需求。我们把所有下拉菜单的逻辑移到Address类里,同时实现国家-州的动态联动,下面是完整的解决方案:
错误原因分析
- 你在
MainApp的__init__里直接访问self.kv.ids.field,但此时kv文件的部件还没完成初始化,导致找不到对应的部件,触发了属性错误。 - 原代码没有把逻辑放在
Address类中,不符合你的需求;同时缺少州选择的UI和联动逻辑。
修改后的代码实现
Python文件
from kivymd.app import MDApp from kivy.lang.builder import Builder from kivymd.uix.menu import MDDropdownMenu from kivy.clock import Clock class Address: def __init__(self, **kwargs): super().__init__(**kwargs) # 定义国家和对应的州数据 self.country_state_data = { 'Japan': ['Tokyo', 'Chiba', 'Kanto'], 'Australia': ['New South Wales', 'Victoria', 'Queensland'], 'Canada': ['Ontario', 'Quebec', 'British Columbia'] } # 初始化国家菜单 self._init_country_menu() # 初始化州菜单(初始为空,选完国家后更新) self._init_state_menu() def _init_country_menu(self): # 创建国家菜单选项 country_items = [{"text": country} for country in self.country_state_data.keys()] self.country_menu = MDDropdownMenu( caller=self.ids.country_field, items=country_items, position="bottom", width_mult=3 ) self.country_menu.bind(on_release=self.on_country_selected) def _init_state_menu(self): # 初始州菜单为空,选完国家后更新 self.state_menu = MDDropdownMenu( caller=self.ids.state_field, items=[], position="bottom", width_mult=3 ) self.state_menu.bind(on_release=self.on_state_selected) def on_country_selected(self, instance_menu, instance_menu_item): def set_country(interval): # 设置国家输入框文本 self.ids.country_field.text = instance_menu_item.text instance_menu.dismiss() # 更新州菜单的选项 self._update_state_menu(instance_menu_item.text) Clock.schedule_once(set_country, 0.1) def _update_state_menu(self, selected_country): # 根据选中的国家获取对应的州列表 states = self.country_state_data.get(selected_country, []) # 更新州菜单的选项 state_items = [{"text": state} for state in states] self.state_menu.items = state_items def on_state_selected(self, instance_menu, instance_menu_item): def set_state(interval): self.ids.state_field.text = instance_menu_item.text instance_menu.dismiss() Clock.schedule_once(set_state, 0.1) def submit(self): # 这里可以添加提交逻辑 country = self.ids.country_field.text state = self.ids.state_field.text print(f"提交的地址:国家={country},州={state}") class MainApp(MDApp): def build(self): return Builder.load_file('../Files/Myapp.kv') if __name__ == '__main__': MainApp().run()
Kivy文件(Myapp.kv)
<Address@MDScreen>: md_bg_color : [102/255,153/255,153/255,1] MDCard : size_hint : None, None size : 300, 450 pos_hint : {"center_x":.5,"center_y":.5} elevation : 15 md_bg_color : [157/255,159/255,48/255,1] padding : 20 spacing : 30 orientation : "vertical" MDTextField: id: country_field pos_hint: {'center_x': .5, 'center_y': .5} size_hint_x: None width: "200dp" hint_text: "Choose Country" required: True helper_text_mode: "on_error" on_focus: if self.focus: root.country_menu.open() MDTextField: id: state_field pos_hint: {'center_x': .5, 'center_y': .5} size_hint_x: None width: "200dp" hint_text: "Choose State" required: True helper_text_mode: "on_error" on_focus: if self.focus and root.ids.country_field.text: root.state_menu.open() MDRoundFlatButton : text : 'Submit' pos_hint : {'center_x':0.5, 'center_y':0.5} font_size : 20 text_color: 0, 0, 0, 1 # 修正原代码的text_color为可见颜色 on_release: root.submit() Widget : size_hint_y : None height : 30 # 设置根部件为Address Address:
关键改进点
- 逻辑迁移:把所有下拉菜单的创建、事件绑定、联动逻辑都移到了
Address类中,完全符合你的需求。 - 动态联动:选中国家后,自动更新州菜单的选项,实现递归动态选择。
- 错误修复:移除了
MainApp中过早访问部件ids的代码,通过在Address类的__init__中初始化菜单,确保部件已完成初始化。 - UI完善:添加了州选择的TextField,修复了提交按钮的文字颜色不可见的问题。
- 数据结构:用字典存储国家-州的映射关系,方便后续扩展更多国家和州。
内容的提问来源于stack exchange,提问作者Biju
相关产品推荐
相关产品推荐

