Kivy调用DropDown.open报已存在父对象错误及代码简化问题咨询
问题解答
初始报错原因
你在KV文件中将DropDown组件直接声明为CustomDropDown的子控件,而DropDown.open()方法执行时会自动将下拉列表挂载到全局窗口根节点上,此时DropDown实例已经存在父级(即你声明的CustomDropDown),因此抛出了无法重复添加到窗口的错误。
最简实现方案
无需额外子类化DropDown和选项控件,直接通过事件绑定即可实现需求,完整代码如下:
main.py
import kivy kivy.require('2.0.0') from kivy.app import App from kivy.uix.anchorlayout import AnchorLayout from kivy.uix.dropdown import DropDown from kivy.uix.label import Label from kivy.uix.textinput import TextInput class CustomDropDown(TextInput): def __init__(self, **kwargs): super().__init__(**kwargs) # 直接创建DropDown实例,不作为自身子控件 self.dropdown = DropDown() # 批量生成选项 for opt in ['Option 1', 'Option 2', 'Option 3']: item = Label(text=opt, size_hint_y=None, height=30) # 绑定点击事件,选中后更新输入框内容并关闭下拉 item.bind(on_touch_down=lambda touch, item=item: self._select_item(item, touch)) self.dropdown.add_widget(item) # 绑定下拉选中事件同步输入框内容 self.dropdown.bind(on_select=lambda instance, x: setattr(self, 'text', x)) def _select_item(self, item, touch): if item.collide_point(*touch.pos): self.dropdown.select(item.text) return True return False def on_touch_down(self, touch): if self.collide_point(*touch.pos): self.dropdown.open(self) # 阻止默认事件避免触发输入框光标跳转 return True return super().on_touch_down(touch) class MainApp(AnchorLayout): pass class MyApp(App): def build(self): return MainApp() if __name__ == '__main__': MyApp().run()
my.kv
<MainApp>: CustomDropDown: text: 'Select an option..' size_hint_y: None height: 30
仅保留CustomDropDown一个子类即可实现全部需求,代码量大幅降低,逻辑也更清晰。
内容的提问来源于stack exchange,提问作者Hannes Ziegler
相关产品推荐
相关产品推荐

