Kivy/KivyMD中如何从另一个类设置类变量以更新按钮文本?
问题描述
在Kivy/KivyMD项目中尝试从另一个类设置按钮文本失败。查看set_people函数,使用PosScreen.people = name修改变量后按钮文本并未改变,尝试通过ids访问组件但不知道如何从其他类实现。
代码片段
test.py
from kivy.properties import StringProperty from kivy.uix.boxlayout import BoxLayout from kivymd.app import MDApp from kivy.uix.screenmanager import ScreenManager, Screen from kivymd.uix.button import MDFlatButton from kivymd.uix.dialog import MDDialog pos_dialog = None class PosScreen(Screen): people = StringProperty("") def __init__(self, **kwargs): super(PosScreen, self).__init__(**kwargs) def on_pre_enter(self, *args): self.people = "No one" def close_dialog(self, *obj): global pos_dialog pos_dialog.dismiss() pos_dialog = None def open_people_dialog(self): global pos_dialog if not pos_dialog: pos_dialog = MDDialog( title="Choose customer", type="custom", content_cls=DialogContentPosAddPeople(), buttons=[ MDFlatButton( text="Close", theme_text_color="Custom", on_release=self.close_dialog ) ] ) pos_dialog.open() class DialogContentPosAddPeople(BoxLayout): def __init__(self, **kwargs): super(DialogContentPosAddPeople, self).__init__(**kwargs) self.set_list_people() def set_list_people(self, text="", search=False): peeps = ["Brian", "AJ", "Nick", "Kevin", "Howie"] def add_name_item(name): self.ids.rv.data.append( { "viewclass": "OneLineListItem", "text": name, "on_release": lambda x=name: self.set_people(x), } ) self.ids.rv.data = [] for name in peeps: if search: if text.lower() in name.lower(): add_name_item(name) else: add_name_item(name) def set_people(self, name): global pos_dialog PosScreen.people = name # it changes the variable but button text doesn't change PosScreen.ids.people_button.text = name # Not accessible NoneType pos_dialog.dismiss() pos_dialog = None return class testApp(MDApp): def build(self): self.theme_cls.primary_palette = "Teal" sm = ScreenManager() sm.add_widget(PosScreen(name="pos")) return sm if __name__ == "__main__": testApp().run()
test.kv
PosScreen: <PosScreen>: name: "pos" people_button: people_button canvas.before: Color: rgba: 72/255, 72/255, 72/255, 1 Rectangle: pos: self.pos size: self.size MDBoxLayout: orientation: "vertical" RelativeLayout: orientation: "vertical" MDRectangleFlatIconButton: id: people_button icon: "account-circle-outline" text: root.people pos_hint:{'x': 0.05, 'center_y': 0.9} md_bg_color: 0, 0, 0, 1 on_release: root.open_people_dialog() <DialogContentPosAddPeople>: rv: rv orientation: "vertical" spacing: dp(10) padding: dp(20) size_hint_y: None height: "240dp" MDBoxLayout: adaptive_height: True MDIconButton: icon: 'magnify' MDTextField: id: search_field hint_text: 'Search name' on_text: root.set_list_people(self.text, True) RecycleView: id: rv key_viewclass: 'viewclass' key_size: 'height' RecycleBoxLayout: padding: dp(10) default_size: None, dp(48) default_size_hint: 1, None size_hint_y: None height: self.minimum_height orientation: 'vertical'
预期效果
点击列表中的任意名称,关闭对话框并将按钮文本改为所选名称。
解决方案
问题核心是你直接操作了类属性而非实例属性,且没有获取到PosScreen的实例引用,以下是具体修复步骤:
1. 传递PosScreen实例给对话框内容类
修改PosScreen的open_people_dialog方法,创建DialogContentPosAddPeople时传入当前屏幕实例:
def open_people_dialog(self): global pos_dialog if not pos_dialog: pos_dialog = MDDialog( title="Choose customer", type="custom", # 传入当前PosScreen实例 content_cls=DialogContentPosAddPeople(pos_screen=self), buttons=[ MDFlatButton( text="Close", theme_text_color="Custom", on_release=self.close_dialog ) ] ) pos_dialog.open()
2. 修改DialogContentPosAddPeople接收实例
在DialogContentPosAddPeople的初始化方法中保存传入的屏幕实例:
class DialogContentPosAddPeople(BoxLayout): def __init__(self, pos_screen, **kwargs): self.pos_screen = pos_screen super(DialogContentPosAddPeople, self).__init__(**kwargs) self.set_list_people()
3. 修改set_people方法操作实例属性
通过保存的实例修改people属性,Kivy的StringProperty会自动同步更新UI:
def set_people(self, name): global pos_dialog # 修改实例的people属性,而非类属性 self.pos_screen.people = name pos_dialog.dismiss() pos_dialog = None
无效原因说明
PosScreen.people = name修改的是类的静态属性,而绑定UI的是当前屏幕实例的people属性,所以不会触发UI更新。PosScreen.ids不存在,ids是每个组件实例独有的属性,必须通过实例才能访问。
内容的提问来源于stack exchange,提问作者blurryrox
相关产品推荐
相关产品推荐

