Kivy/KivyMD:为动态添加的DropDownItem添加选中变更触发方法
动态添加MDDropDownItem时选中项变更事件触发方案
你遇到的问题核心有两点:
MDDropDownItem的on_select事件不会在手动调用set_item()时自动触发,需要手动派发事件- 绑定事件的回调函数参数不符合Kivy的要求——Kivy的事件回调必须接收触发事件的控件实例作为第一个参数
下面提供两种可行的解决办法:
方法一:手动触发on_select事件
修改Set_DropDown_Item方法,在设置选中项后主动派发on_select事件,同时调整回调函数的参数:
def DDI_Selection_Changed(self, instance, value): toast(f'SELECTION CHANGED: {value}') def Set_DropDown_Item(self, drop_down_item, menu, text_item): drop_down_item.set_item(text_item) # 手动触发on_select事件,传入选中的值 drop_down_item.dispatch('on_select', text_item) menu.dismiss()
方法二:绑定current_item属性变化
这种方式更通用,不管是通过菜单选择还是其他方式修改选中项,只要current_item属性变化就会触发回调:
在Button_CreateDDI__On_Click方法中,把绑定on_select的代码换成绑定current_item:
# 替换原来的self.myDdi.bind(on_select = self.DDI_Selection_Changed) self.myDdi.bind(current_item = self.DDI_Selection_Changed)
同时调整回调函数的参数(Kivy属性绑定的回调接收控件实例、新值两个参数):
def DDI_Selection_Changed(self, instance, new_value): toast(f'SELECTION CHANGED: {new_value}')
修改后的完整代码(方法二示例)
from kivy.lang import Builder from kivymd.app import MDApp from kivymd.uix.screen import MDScreen from kivymd.toast import toast from kivymd.uix.menu import MDDropdownMenu from kivymd.uix.dropdownitem.dropdownitem import MDDropDownItem from kivy.metrics import dp Builder.load_string( """ <View>: MDGridLayout: rows: 3 id: layout padding: 100, 50, 100, 50 spacing: 0, 50 MDRaisedButton: text: 'CREATE DDI' on_release: root.Button_CreateDDI__On_Click() MDRaisedButton: id: button_check disabled: True text: 'CHECK SELECTION' on_release: root.Button_CheckSelection_On_Click() """ ) class View(MDScreen): def __init__(self, **kwargs): super(View, self).__init__(**kwargs) def Button_CreateDDI__On_Click(self): self.myDdi = MDDropDownItem() self.myDdi.text = 'SELECT POSITION' myMenu, scratch = self.Create_DropDown_Widget(self.myDdi, ['POS 1', 'POS 2', 'POS 3'], width=4) self.myDdi.on_release = myMenu.open # 绑定current_item属性变化,替换原来的on_select绑定 self.myDdi.bind(current_item=self.DDI_Selection_Changed) self.ids.button_check.disabled = False self.ids.layout.add_widget(self.myDdi) def Button_CheckSelection_On_Click(self): toast(f'CURRENT VALUE: {self.myDdi.current_item}') def DDI_Selection_Changed(self, instance, new_value): toast(f'SELECTION CHANGED: {new_value}') def Create_DropDown_Widget(self, drop_down_item, item_list, width): items_collection = [ { "viewclass": "OneLineListItem", "text": item_list[i], "height": dp(56), "on_release": lambda x=item_list[i]: self.Set_DropDown_Item(drop_down_item, menu, x), } for i in range(len(item_list)) ] menu = MDDropdownMenu(caller=drop_down_item, items=items_collection, width_mult=width) return menu, items_collection def Set_DropDown_Item(self, drop_down_item, menu, text_item): drop_down_item.set_item(text_item) menu.dismiss() class MainApp(MDApp): def __init__(self, **kwargs): super().__init__(**kwargs) self.View = View() def build(self): self.title = 'DROP DOWN ITEM ADDED DYNAMICALLY' return self.View if __name__ == '__main__': MainApp().run()
内容的提问来源于stack exchange,提问作者eljamba
相关产品推荐
相关产品推荐

