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

Kivy自定义SpinnerButton首次交互时UI未正确更新问题求助

问题原因分析

你绑定name_button的on_release事件来触发职业更新,但这个事件是点击按钮打开下拉框的瞬间就执行的,此时下拉框还没完成名字选择,name_button.text还是旧值(第一次点击时是初始的"Name"),自然匹配不到对应职业;第二次点击时,name_button.text已经是上一次选中的名字,所以能触发职业更新。

解决方案

把对on_release事件的绑定改成监听name_button的text属性变化,这样当下拉框选中名字、text更新的瞬间,就能立刻触发职业按钮的更新。

修改后的完整代码

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.properties import ListProperty, StringProperty
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.modalview import ModalView
from kivy.core.window import Window

class GridDropDown(ModalView):
    def __init__(self, button_ref, options, **kwargs):
        super(GridDropDown, self).__init__(**kwargs)
        self.size_hint = (None, None)
        self.width = Window.width * 0.6
        self.auto_dismiss = False

        self.button_ref = button_ref

        grid_layout = GridLayout(cols=1, spacing=5, size_hint_y=None)
        grid_layout.bind(minimum_height=grid_layout.setter('height'))

        scroll_view = ScrollView(size_hint=(1, None), size=(self.width, Window.height * 0.5))
        scroll_view.do_scroll_x = False

        for option in options:
            btn = Button(text=option, size_hint_y=None, height=40, size_hint_x=1)
            btn.bind(on_release=self.on_select)
            grid_layout.add_widget(btn)

        scroll_view.add_widget(grid_layout)
        self.add_widget(scroll_view)

    def on_select(self, instance):
        self.button_ref.text = instance.text
        self.dismiss()

class CustomSpinnerButton(Button):
    options = ListProperty([])
    text = StringProperty('')

    def __init__(self, **kwargs):
        super(CustomSpinnerButton, self).__init__(**kwargs)
        self.bind(on_release=self.open_dropdown)

    def open_dropdown(self, *args):
        dropdown = GridDropDown(button_ref=self, options=self.options)
        dropdown.open()

    def on_option_select(self, value):
            self.text = value

class MainScreen(BoxLayout):
    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)
        self.orientation = 'vertical'
        self.padding = 5
        self.spacing = 10

        self.name_button = CustomSpinnerButton(text='Name', font_size='20sp', options=["Alice", "Bob", "Charlie"])
        self.add_widget(self.name_button)
        self.profession_button = CustomSpinnerButton(text='Profession', font_size='20sp', options=["Engineer", "Doctor", "Artist"])
        self.add_widget(self.profession_button)

        # 关键改动:监听text属性变化,而非on_release事件
        self.name_button.bind(text=self.on_name_selected)

    def on_name_selected(self, instance, new_text):
        name_to_profession = {
            'Alice': 'Engineer', 'Bob': 'Doctor', 'Charlie': 'Artist'
        }
        profession = name_to_profession.get(new_text, '')
        if profession:
            self.profession_button.text = profession

class MyApp(App):
    def build(self):
        return MainScreen()

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

关键改动点

  1. 事件绑定调整:将self.name_button.bind(on_release=self.on_name_selected)改为self.name_button.bind(text=self.on_name_selected),监听按钮文本的变化而非点击释放事件。
  2. 回调函数参数调整:on_name_selected函数新增new_text参数,接收更新后的文本值,直接用这个值匹配对应职业,确保拿到的是最新选中的名字。

这样修改后,每次选中名字时,name_button.text更新的瞬间就会触发职业按钮的同步更新,首次点击即可生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 03:12:36