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

Kivy食谱应用删除食材时触发'DropDown'无'button'属性错误求助

问题原因与解决方案

错误原因

你遇到的'DropDown' object has no attribute 'button'错误,是因为Kivy的DropDown组件本身没有button属性,你错误地尝试直接通过self.ingredient_dropdown.button.text获取选中项。此外,DropDown的正确用法需要绑定到一个触发按钮,而非直接添加到布局中。

修复方案

我们需要调整RemoveIngredientPopup的实现,添加触发DropDown的按钮,同时记录用户选中的食材:

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.dropdown import DropDown


# 共享的食材列表(替代硬编码,方便后续扩展)
INGREDIENTS_LIST = ['salt', 'pepper', 'sugar', 'flour']

class IngredientPopup(Popup):
    def __init__(self, **kwargs):
        super(IngredientPopup, self).__init__(**kwargs)

        layout = GridLayout(cols=2)

        self.current_ingredients_label = Label(text='Current Ingredients:\n')
        layout.add_widget(self.current_ingredients_label)

        add_button = Button(text='Add Ingredient')
        add_button.bind(on_press=self.add_ingredient_popup)
        layout.add_widget(add_button)

        remove_button = Button(text='Remove Ingredient')
        remove_button.bind(on_press=self.remove_ingredient_popup)
        layout.add_widget(remove_button)

        self.content = layout
        self.load_ingredients_list()

    def add_ingredient_popup(self, instance):
        add_popup = AddIngredientPopup()
        add_popup.bind(on_dismiss=self.update_ingredient_list)
        add_popup.open()

    def remove_ingredient_popup(self, instance):
        remove_popup = RemoveIngredientPopup()
        remove_popup.bind(on_dismiss=self.update_ingredient_list)
        remove_popup.open()

    def load_ingredients_list(self):
        global INGREDIENTS_LIST
        self.current_ingredients_label.text = 'Current Ingredients:\n' + '\n'.join(INGREDIENTS_LIST)

    def update_ingredient_list(self, instance):
        self.load_ingredients_list()

class AddIngredientPopup(Popup):
    def __init__(self, **kwargs):
        super(AddIngredientPopup, self).__init__(**kwargs)

        layout = GridLayout(cols=2)

        ingredient_name_label = Label(text='Ingredient Name:')
        layout.add_widget(ingredient_name_label)

        self.ingredient_name_input = TextInput()
        layout.add_widget(self.ingredient_name_input)

        add_ingredient_button = Button(text='Add')
        add_ingredient_button.bind(on_press=self.add_ingredient)
        layout.add_widget(add_ingredient_button)

        self.content = layout

    def add_ingredient(self, instance):
        global INGREDIENTS_LIST
        ingredient_name = self.ingredient_name_input.text.strip()
        if ingredient_name and ingredient_name not in INGREDIENTS_LIST:
            INGREDIENTS_LIST.append(ingredient_name)
            print(f"Added ingredient: {ingredient_name}")
        self.dismiss()


class RemoveIngredientPopup(Popup):
    def __init__(self, **kwargs):
        super(RemoveIngredientPopup, self).__init__(**kwargs)
        self.selected_ingredient = None  # 存储选中的食材

        layout = GridLayout(cols=2)

        ingredient_label = Label(text='Select Ingredient:')
        layout.add_widget(ingredient_label)

        # 1. 创建触发DropDown的主按钮
        self.dropdown_trigger = Button(text='Choose an ingredient', size_hint_y=None, height=44)
        layout.add_widget(self.dropdown_trigger)

        # 2. 初始化DropDown并绑定到主按钮
        self.ingredient_dropdown = DropDown()
        self.load_ingredients_list()
        self.dropdown_trigger.bind(on_release=self.ingredient_dropdown.open)
        self.ingredient_dropdown.bind(on_select=self.on_dropdown_select)

        remove_ingredient_button = Button(text='Remove')
        remove_ingredient_button.bind(on_press=self.remove_ingredient)
        layout.add_widget(remove_ingredient_button)

        self.content = layout

    def load_ingredients_list(self):
        global INGREDIENTS_LIST
        self.ingredient_dropdown.clear_widgets()  # 清空旧选项
        for ingredient in INGREDIENTS_LIST:
            btn = Button(text=ingredient, size_hint_y=None, height=44)
            # 点击下拉选项时,将值传递给DropDown的select方法
            btn.bind(on_release=lambda btn: self.ingredient_dropdown.select(btn.text))
            self.ingredient_dropdown.add_widget(btn)

    def on_dropdown_select(self, instance, value):
        # 捕获选中的值并更新主按钮文本
        self.selected_ingredient = value
        self.dropdown_trigger.text = value

    def remove_ingredient(self, instance):
        global INGREDIENTS_LIST
        if self.selected_ingredient and self.selected_ingredient in INGREDIENTS_LIST:
            INGREDIENTS_LIST.remove(self.selected_ingredient)
            print(f"Removed ingredient: {self.selected_ingredient}")
        self.dismiss()


class TopStorage(Button):
    def __init__(self, **kwargs):
        super(TopStorage, self).__init__(**kwargs)
        self.opacity = 0
        self.size_hint = (None, None)
        self.size = (0, 0)
        
    def on_press(self):
        popup = IngredientPopup(title='Top Storage', size_hint=(None, None), size=(400, 400))
        popup.open()

class TopFridge(Button):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.opacity = 0
        self.size_hint = (None, None)
        self.size = (0, 0)
        
    def on_press(self):
        popup = Popup(title='Top Fridge', size_hint=(None, None), size=(400, 400))
        label = Label(text='top fridge')
        popup.content = label
        popup.open()

class BottomFridge(Button):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.opacity = 0
        self.size_hint = (None, None)
        self.size = (0, 0)
        
    def on_press(self):
        popup = Popup(title='Bottom Fridge', size_hint=(None, None), size=(400, 400))
        label = Label(text='bottom fridge')
        popup.content = label
        popup.open()

class Pot(Button):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.opacity = 0
        self.size_hint = (None, None)
        self.size = (0, 0)
        
    def on_press(self):
        popup = Popup(title='Pot', size_hint=(None, None), size=(400, 400))
        label = Label(text='pot')
        popup.content = label
        popup.open()


class MyApp(App):
    def build(self):
        layout = FloatLayout()
        background = Image(source='C:/Users/private/Desktop/KuhinjaV2.jpg')

        button1 = TopStorage(text='storage gore')
        button2 = TopFridge(text='frizider gore')
        button3 = BottomFridge(text='frizider dole')
        button4 = Pot(text='pot')

        button1.pos_hint = {'x': 0.08, 'y': 0.75}
        button1.size_hint = (0.85, 0.2)

        button2.pos_hint = {'x': 0.8, 'y': 0.4}
        button2.size_hint = (0.15, 0.2)

        button3.pos_hint = {'x': 0.8, 'y': 0.035}
        button3.size_hint = (0.15, 0.35)

        button4.pos_hint = {'x': 0.094, 'y': 0.38}
        button4.size_hint = (0.07, 0.07)

        layout.add_widget(background)
        layout.add_widget(button1)
        layout.add_widget(button2)
        layout.add_widget(button3)
        layout.add_widget(button4)
    
        return layout

if __name__ == '__main__':
    MyApp().run()

关键修改说明

  1. 添加共享食材列表:用全局变量INGREDIENTS_LIST替代多处硬编码,确保添加/移除操作后所有弹窗的食材列表同步更新
  2. DropDown正确绑定:
    • 创建dropdown_trigger按钮作为DropDown的触发入口,而非直接将DropDown加入布局
    • 为下拉选项按钮绑定on_release事件,通过DropDown.select()传递选中值
    • 监听DropDown的on_select事件,记录选中的食材并更新触发按钮的文本
  3. 修复移除逻辑:移除操作前先检查是否有选中食材,避免空值报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 07:35:00