You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kivy/KivyMD:为动态添加的DropDownItem添加选中变更触发方法

动态添加MDDropDownItem时选中项变更事件触发方案

你遇到的问题核心有两点:

  1. MDDropDownItem的on_select事件不会在手动调用set_item()时自动触发,需要手动派发事件
  2. 绑定事件的回调函数参数不符合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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 14:04:55