0

I developed an UI with Python/Kivy/KivyMD. It is a simple app in which three screens are defined by three different classes: View1, View2 and View3. In the class 'MainApp' a screen manager is defined and used to switch between screens. The switch between screens occurs when the user clicks a button and is managed by an event in which the screen manager is recalled. The third screen (View3) contains a label too. How can I pass an argument/variable from View1 to View3? I would like to show some text in this label which comes from View1 (see commented lines). And in general, how can a global variable inside the View3 be defined from another class, such as View1? In particular, I would like to pass a value in View1 to a variable defined in View1 (see SwitchToScreen2). Here is the code:

from kivy.lang import Builder
from kivymd.app import MDApp
#from kivy.uix.screenmanager import NoTransition, SwapTransition, SlideTransition, FallOutTransition
from kivymd.uix.transition import MDSwapTransition, MDSlideTransition
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)
        # MAYBE INITIALIZE HERE THE VARIABLE myString
        # self.myString = 
        
    def switch_to_screen1(self):
        MDApp.get_running_app().sm.current = 'view1'        
    
    def WriteInTheLabel(self):
        self.ids.label_view3.text = 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')
        # THE FOLLOWING LINES GAVE ME A NAME ERROR: 'myString' is not defined
        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()
eljamba
  • 171
  • 1
  • 2
  • 11

1 Answers1

0

In your switch_to_screen2() method you can use the manager property of the Screen to get its ScreenManager. Then use the get_screen() method of ScreenManager to get a reference to the instance of a Screen:

def switch_to_screen2(self):
    MDApp.get_running_app().sm.current = 'view2'

    # Pass some text here
    # How can I find an istance of View3 from here?
    # MDApp.get_running_app().view3.WriteInTheLabel('MSG FROM VIEW 1')
    view3 = self.manager.get_screen('view3')
    print(view3.ids.label_view3.text)

Note that your definition of myString in View3 is creating a class level variable rather than an instance variable. See the documentation for details. It can get complicated when you use a class variable as an instance variable (i.e., when you use view3.myString vs View3.myString), see this Stack Overflow question. Anyway, your error is coming from the line:

self.ids.label_view3.text = myString + ' RECEIVED'

You need to refer to myString as either self.myString or (since it is a class variable), as View3.myString. I suggest defining myString in your __init__() method (as you proposed in the comment), then you always refer to it as an instance variable.

John Anderson
  • 35,991
  • 4
  • 13
  • 36
  • Thank you! Actually my question was broader, so I edited the question adding a variable in class __View3__ and some code in __SwitchToScreen2__ method to pass a value to that variable. Maybe I need an instance of __View3__ in __View1__? But how can I call it if it is managed by the screen manager in Main App? I have some global variables in __View3__ (_myString_ in this example) that have to be defined from __View1__. Once they are defined, are modified in __View3__ and shown as labels for example. – eljamba Apr 02 '23 at 11:10