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

PC端Python Kivy应用添加widget后无响应 MDDropdownMenu重叠问题

问题根因
  • 类名引用错误:自定义下拉类命名为MyListDropdownValue,但在StartScreen.open_listdropdown方法中错误调用了不存在的MyListDropdownProduct类,直接触发运行报错。
  • 错误调用add_widget方法:MDDropdownMenu属于弹出层悬浮组件,本身不需要添加到父布局的控件树中,强制添加会打乱布局结构、破坏组件本身的生命周期管理,是选中选项后应用停止响应的核心原因。
  • 实例管理逻辑错误:依赖self.children长度判断是否新建实例的逻辑不可靠,原布局本身就有默认子控件,会导致后续取children[0]时拿到错误的控件对象,调用方法直接崩溃。
  • 嵌套定义冗余:MyListDropdownValue本身已经继承了MDDropdownMenu,内部不需要再嵌套创建新的MDDropdownMenu实例,多重实例会导致事件响应混乱。
修复方案

核心逻辑是将下拉实例存为StartScreen的类属性管理,不需要添加到布局树,即可避免重复创建实例也不会打乱布局结构,修复后的完整代码如下:

# kivymd 0.104.2
# kivy 2.0.0

from kivy.clock import Clock
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import ObjectProperty
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.menu import MDDropdownMenu

kv_str = """
<StartScreen>:
    startscreen_textfield_1: textfield_id
    BoxLayout:
        orientation: "vertical"
        BoxLayout:
            size_hint: 1, 0.5
        BoxLayout:
            size_hint: 1, 0.5
            orientation: "vertical"
            BoxLayout:
                MDTextField:
                    id: textfield_id
                    on_text:
                        root.open_listdropdown(textfield_id)
            BoxLayout:
                MDTextField:
            BoxLayout:
                MDTextField:
"""
P_LIST = ["ASD", "SDF", "AASD"]

def search_product(prefix):
    return list(filter(lambda l: l.startswith(prefix), P_LIST))


class MyListDropdownValue(MDDropdownMenu):
    def __init__(self, dropdown_list, **kwargs):
        super().__init__(caller=dropdown_list, width_mult=5, **kwargs)
        self.dropdown_list_id = dropdown_list

    def list_dropdown(self):
        if len(self.dropdown_list_id.text) == 0:
            self.dismiss()
            return
        prefix = self.dropdown_list_id.text.upper()
        filtered_list = search_product(prefix)
        if not filtered_list:
            self.dismiss()
            return
        self.items = [
            {
                'text': f'{value}',
                "height": dp(56),
                "viewclass": "OneLineListItem",
                "on_release": lambda x=f"{value}": self.set_item(x)
            } 
            for value in filtered_list
        ]
        self.open()

    def set_item(self, value):
        def set_item(interval):
            self.dropdown_list_id.text = value
            self.dismiss()
        Clock.schedule_once(set_item, 0.1)


class StartScreen(BoxLayout):
    startscreen_textfield_1 = ObjectProperty()
    listdropdown = None # 存储下拉实例的属性

    def open_listdropdown(self, input_id):
        # 不存在实例则新建,不用add到布局
        if not self.listdropdown:
            self.listdropdown = MyListDropdownValue(input_id)
        else:
            # 存在旧实例先关闭
            self.listdropdown.dismiss()
        # 刷新下拉内容展示
        self.listdropdown.list_dropdown()


kv = Builder.load_string(kv_str)

class Program(MDApp):
    def build(self):
        self.screen = StartScreen()
        return self.screen


def main():
    app = Program()
    app.run()


if __name__ == "__main__":
    main()

内容的提问来源于stack exchange,提问作者Алексей Елизаров

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 14:45:05