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

Python/Kivy/KivyMD:通过ScreenManager调用屏幕类时如何传递参数

问题解决:KivyMD屏幕间变量传递与命名错误修复

问题背景

使用Python/Kivy/KivyMD开发UI应用,包含View1、View2、View3三个屏幕,通过MDScreenManager管理切换。当前需求:

  • 将View1的参数传递到View3,并在View3的Label组件中显示该文本
  • 实现从View1定义View3的全局变量
    现有代码执行时出现myString is not defined命名错误。

错误原因

在View3的WriteInTheLabel方法中,直接使用myString变量,但未通过self引用当前实例的属性。虽然View3类定义了类变量myString,但在View1中赋值的是View3实例的属性,方法内必须通过self访问实例属性,否则会被视为未定义的局部变量。

解决方案

1. 修复View3的方法实现

修改WriteInTheLabel方法,通过self.myString访问实例属性:

def WriteInTheLabel(self):
    self.ids.label_view3.text = self.myString + ' RECEIVED'

2. 显式初始化实例变量(可选)

为避免类变量与实例变量混淆,在View3的__init__方法中显式初始化实例变量:

def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.myString = ''  # 初始化实例变量,覆盖类变量默认值

3. 类级全局变量的定义方式(需求2实现)

如果需要定义View3的类级全局变量(所有View3实例共享),可以直接通过类名访问赋值:

# 在View1的switch_to_screen2方法中
View3.myString = '类级全局消息'
# View3中访问时可以用类名或self(若实例未覆盖该变量)
self.ids.label_view3.text = View3.myString + ' RECEIVED'

修改后的完整代码

from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.transition import MDSwapTransition
from kivymd.uix.screenmanager import MDScreenManager
from kivymd.uix.screen import MDScreen
from kivymd.uix.tab import MDTabsBase
from kivymd.uix.floatlayout import MDFloatLayout


Builder.load_string(
    """   
<View3>:
    MDRelativeLayout:
        MDLabel:
            id: label_view3
            halign: 'center'
        MDRaisedButton:
            text: 'GO TO VIEW 1'
            pos_hint: {'center_x': 0.7, 'center_y': 0.7}
            on_release: root.switch_to_screen1()
    

<View2>:
    MDRaisedButton:
        text: 'GO TO VIEW 3'
        pos_hint: {'center_x': 0.5, 'center_y': 0.5}
        on_release: root.switch_to_screen3()

    

<View1>:
    sm_view1: sm_view1
    tabs: tabs
    
    MDAnchorLayout:
        anchor_x: 'center'
        anchor_y: 'top'   
        MDBoxLayout:
            size_hint: 1, 0.2
            orientation: 'vertical'
            MDTabs:
                id: tabs
                on_tab_switch: root.Tab_Switch(*args)
    

    MDAnchorLayout:
        anchor_x: 'center'
        anchor_y: 'bottom'   
        MDScreenManager:
            size_hint: 1, 0.8
            id: sm_view1
            
            MDScreen:
                name: 'screen1'
                MDLabel:
                    text: 'VIEW 1'
                    halign: 'center'
                    
            MDScreen:
                name: 'screen2'
                MDRaisedButton:
                    text: 'GO TO VIEW 2'
                    pos_hint: {'center_x': 0.3, 'center_y': 0.3}
                    on_release: root.switch_to_screen2()
    
"""
)

    
class Tab(MDFloatLayout, MDTabsBase):
    '''Class implementing content for a tab.'''

    

class View3(MDScreen):
    myString = ''  # 类变量,可作为全局默认值
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.myString = ''  # 初始化实例变量
    
    def switch_to_screen1(self):
        MDApp.get_running_app().sm.current = 'view1'        
    
    def WriteInTheLabel(self):
        self.ids.label_view3.text = self.myString + ' RECEIVED'

    

class View2(MDScreen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)      
    
    def switch_to_screen3(self):
        MDApp.get_running_app().sm.current = 'view3'

        

class View1(MDScreen):
    sm_view1: MDScreenManager
    tabs: Tab
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        
        self.tabsTitles = ['SCREEN 1', 'SCREEN 2']
        self.Tab_Start()
        
        
    def Tab_Start(self):
        for label in self.tabsTitles:
            self.ids.tabs.add_widget(Tab(title=label))
        
    
    def Tab_Switch(
        self, instance_tabs, instance_tab, instance_tab_label, tab_text
    ):
        '''Called when switching tabs.

        :type instance_tabs: <kivymd.uix.tab.MDTabs object>;
        :param instance_tab: <__main__.Tab object>;
        :param instance_tab_label: <kivymd.uix.tab.MDTabsLabel object>;
        :param tab_text: text or name icon of tab;
        '''
        if tab_text == self.tabsTitles[0]:
            self.sm_view1.current = 'screen1'
        elif tab_text == self.tabsTitles[1]:
            self.sm_view1.current = 'screen2'
            
    def switch_to_screen2(self):
        MDApp.get_running_app().sm.current = 'view2'

        view3 = self.manager.get_screen('view3')
        view3.myString = 'MSG FROM VIEW 1'
        view3.WriteInTheLabel()



class MainApp(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)        
        
        self.sm = MDScreenManager(transition = MDSwapTransition())
        self.sm.add_widget(View1(name="view1"))
        self.sm.add_widget(View2(name="view2"))
        self.sm.add_widget(View3(name="view3"))
        

    def build(self):        
        return self.sm
    
    
if __name__ == '__main__':
    MainApp().run()

验证效果

运行修改后的代码,点击View1中Screen2的GO TO VIEW 2按钮,此时View3的myString已被赋值,当后续切换到View3时,Label会显示MSG FROM VIEW 1 RECEIVED。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 15:47:02