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()
关键改动点
- 事件绑定调整:将
self.name_button.bind(on_release=self.on_name_selected)改为self.name_button.bind(text=self.on_name_selected),监听按钮文本的变化而非点击释放事件。 - 回调函数参数调整:
on_name_selected函数新增new_text参数,接收更新后的文本值,直接用这个值匹配对应职业,确保拿到的是最新选中的名字。
这样修改后,每次选中名字时,name_button.text更新的瞬间就会触发职业按钮的同步更新,首次点击即可生效。
内容的提问来源于stack exchange,提问作者Douglas Nunes
相关产品推荐
相关产品推荐

