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

使用Kivy库实现多下拉列表时部分下拉菜单失效问题求助

问题:Kivy多个下拉菜单仅部分正常工作

需要实现多个下拉列表,但部分下拉菜单无法正常工作。期望构造函数中的4个列表分别对应各自的主按钮正常显示并可使用,但实际仅有1个或偶尔2个下拉菜单能正常工作。

相关代码如下:

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.app import App

class MidTopBar():
    def __init__(self):

        self.dropDownLabels = {
            "File"  : ['Example1', 'Example2','Example3', 'Example4'],
            "Edit"  : ['Example5', 'Example6','Example7', 'Example8'],
            "View"  : ['Example9', 'Example10','Example11', 'Example12'],
            "Help"  : ['Example13', 'Example14','Example15', 'Example16'],
        }
        self.generate()

         
    def _generateDropdown(self, name, list):
        dropdown = DropDown(auto_width = True,
                            width = 300)

        for index in range(len(list)):
            btn = Button(text=list[index],
                         halign = 'left',
                         valign = 'center',
                         padding_x= 20,
                         size_hint_y=None,
                         background_color = (1, 1, 1, 1))

            btn.bind(on_release=lambda btn: dropdown.select(list[index]))
            btn.bind(size= btn.setter('text_size'))
            dropdown.add_widget(btn)

        mainbutton = Button(text = name)

        dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
        mainbutton.bind(on_release=dropdown.open)

        return mainbutton
    
    def _dropDowns(self):
        dropDownList = []
        for key in self.dropDownLabels:
            dropDownList.append(self._generateDropdown(name= key, list = self.dropDownLabels[key]))
        return dropDownList
                
    def generate(self):
        dropDownList = self._dropDowns()
        self.Box = BoxLayout()
        for dropDown in dropDownList:
            self.Box.add_widget(dropDown)
        self.emptyBox = BoxLayout()
        self.superBox = BoxLayout(orientation='vertical')
        self.superBox.add_widget(self.Box)
        self.superBox.add_widget(self.emptyBox)
        
class Example(App):
    
    def build(self):
        midTopBar       :object = MidTopBar().superBox
        return midTopBar

# Run the App of TextInput Widget in kivy
if __name__ == "__main__":
    Example().run()

问题原因

  1. Lambda闭包陷阱:循环中绑定的lambda btn: dropdown.select(list[index])并未捕获当前循环的index值,而是引用了循环变量的最终值。所有下拉项点击后都会选中对应列表的最后一个元素,导致功能异常。
  2. Dropdown被垃圾回收:_generateDropdown方法中创建的Dropdown对象没有持久化引用,方法执行完毕后可能被Python垃圾回收机制回收,导致部分下拉菜单无法打开。

解决方案

修改_generateDropdown方法,解决闭包问题并保存Dropdown引用:

def _generateDropdown(self, name, list):
    dropdown = DropDown(auto_width=True, width=300)

    for item in list:
        btn = Button(text=item,
                     halign='left',
                     valign='center',
                     padding_x=20,
                     size_hint_y=None,
                     background_color=(1, 1, 1, 1))
        # 通过默认参数捕获当前item,避免闭包陷阱
        btn.bind(on_release=lambda btn, x=item: dropdown.select(x))
        btn.bind(size=btn.setter('text_size'))
        dropdown.add_widget(btn)

    mainbutton = Button(text=name)
    # 将Dropdown绑定到主按钮属性,防止被垃圾回收
    mainbutton.dropdown = dropdown
    dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
    mainbutton.bind(on_release=dropdown.open)

    return mainbutton

修改说明

  • 遍历列表时直接使用item而非索引,通过lambda的默认参数x=item捕获当前元素,避免闭包引用循环变量的问题。
  • 将dropdown赋值给mainbutton.dropdown,给Dropdown对象添加持久化引用,防止被垃圾回收。

内容的提问来源于stack exchange,提问作者Reza Besharat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:47:36