Global Variable on kivy

1,080 views
Skip to first unread message

coutinh...@gmail.com

unread,
Mar 2, 2022, 10:09:17 AM3/2/22
to Kivy users support
Hello everyone,

I'm using the Pyrebase library and I'm very satisfied with what it offers me.

https://github.com/thisbejim/Pyrebase#storage

In this library we login with email and password and save it in a user variable so that we can send user as a token in Firebase queries.

Turns out my login screen works beautifully but the query screen is in another class.

Two questions:

1 - Can I use the value of a variable from another class?
2 - Any tips to make the user variable accessible anywhere in the kivy code?

Elliot Garbus

unread,
Mar 2, 2022, 10:35:56 AM3/2/22
to kivy-...@googlegroups.com

You can access any Class attribute by walking the widget tree in kivy, and using ids.

You can start with app.root and build a chain to touch any class instance attribute.

Accessing screens you would use the get_screen() method of the screenmanager.

 

You put attributes in the App class and they can easily be accessed from anywhere in your code.

In kv: app.my_attribute

 

In Python:

app = App.get_running_app()

app.my_attribute = ‘new value’

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/7642ccf3-4545-47c2-8b13-aa3c74bcdbean%40googlegroups.com.

 

Elias Coutinho

unread,
Mar 2, 2022, 2:17:20 PM3/2/22
to kivy-...@googlegroups.com
Forgive my lack of clarity but I didn't explain properly.

The login screen that has the value I want is in a ScreenManager with id: sm

The screen that should receive this value is in another ScreenManager with id: screen_manager

I'm trying to get the value of a user variable as follows:

self.manager.get_screen('screen_login').ids.user['idToken']

I could not decipher this problem.



--
Elias Coutinho.
Aprender sobre alguns assuntos é fundamental.
Aprender sobre Deus é indiscutivelmente o melhor conteúdo.

Elliot Garbus

unread,
Mar 2, 2022, 3:26:53 PM3/2/22
to kivy-...@googlegroups.com

You have not provided enough information for me to help you.  Lets assume a widget tree:

 

Root:
    ScreenManager:
        id: sm
        LoginScreen:
            name: 'login_screen'

    ScreenManager:
        id: screen_manager
        ReadFromLogin:

<ReadFromLogin@ Screen>:
    Button:
        text: 'Get Login Info'
        on_release: print(app.root.ids.sm.get_screen('login_screen).login_screen_attribute)

 

If this is not helpful, share your code or a simplified widget tree.

Elias Coutinho

unread,
Mar 2, 2022, 4:46:53 PM3/2/22
to kivy-...@googlegroups.com
Come on!

On line 188 I have my first ScreenManager whose id: sm, it has a screen with name: 'screen_login' (lines 191 and 83), this screen has a class called TelaLogin(Screen), inside this class there is a variable called user.

On line 70 I have my second ScreenManager whose id: screen_manager, it has a screen with name: "nova_tella" (line 156 and 72), I would like to access the ScreenManager sm screen and get the content of the user variable and be able to use it in any part of the current screen that is active.

I would like to learn this process in both kv and py file


Elliot Garbus

unread,
Mar 2, 2022, 6:53:28 PM3/2/22
to kivy-...@googlegroups.com

To access the user variable from any where in kv:

app.root.get_screen('tela_login').user

 

app.root is the root widget, in this case this is the screen manager, because this is the root widget, we do not need to use the ids.

 

app.root.get_screen('tela_login') provides the screen widget and

app.root.get_screen('tela_login').user  provides the access the user attribute.

 

In python you can do effectively the same thing, start by getting the app with the call to App.get_running_app()

app = App.get_running_app() # I like to create a variable called app so the “kv string” looks the same in python and kv

app.root.get_screen('tela_login').user

 

 

I often find it helpful to print out these elements to check that I am addressing the correct widget.

 

Lets try to do this the other way – lets assume you want to access a variable from the screen ‘nova_tella’

app.root.get_screen(‘main’).ids.screen_manager.get_screen("nova_tela").ids.rv2  # this is the recycleview on the screen.

 

 

Let me know how this works out for you.

Elias Coutinho

unread,
Mar 2, 2022, 8:26:03 PM3/2/22
to kivy-...@googlegroups.com
image.png

I am unable to run the project.
I use kivymd and there is no App but MDApp.
Trying to simulate with App doing the import it presents the following error:

     app.root.get_screen('tela_login').user
 AttributeError: 'NoneType' object has no attribute 'root'


In this code, I got the following error:

nuser = MDApp.root.get_screen('tela_login').user

      nuuser = MDApp.root.get_screen('screen_login').user
  AttributeError: type object 'MDApp' has no attribute 'root'

Elliot Garbus

unread,
Mar 2, 2022, 9:01:03 PM3/2/22
to kivy-...@googlegroups.com

Ahh… just use MDApp.get_running_app()

 

Inside the AppDesktop you can just use self, self is the AppDesktop.

 

Don’t run this code at the class level, put it in a method.

 

 

From: Elias Coutinho
Sent: Wednesday, March 2, 2022 6:26 PM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] Global Variable on kivy

 

Elliot Garbus

unread,
Mar 2, 2022, 9:28:53 PM3/2/22
to kivy-...@googlegroups.com

Here is an example.  (this code may look familiar).  Take a look at the on_start method and the series of print statements.

 

from kivy.lang import Builder
from kivy.properties import ObjectProperty

from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout

KV =
'''
<ContentNavigationDrawer>:

    ScrollView:

        MDList:

            OneLineListItem:
                text: "Screen 1"
                on_press:
                    root.nav_drawer.set_state("close")
                   root.screen_manager.current = "scr 1"

            OneLineListItem:
                text: "Screen 2"
                on_press:
                    root.nav_drawer.set_state("close")
                    root.screen_manager.current = "scr 2"

<LabelMDScreen@MDScreen>:
    MDLabel:
        id: label
        text: "Screen 2"
        halign: "center"

BoxLayout:
    orientation: 'vertical'

    MDToolbar:
        id: toolbar
        # pos_hint: {"top": 1}
        elevation: 10
        title: "MDNavigationDrawer"
        left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]

    MDNavigationLayout:
        # x: toolbar.height

        ScreenManager:
            id: screen_manager

            MDScreen:
                name: "scr 1"
                # size_hint_y: None
                # height: root.height - toolbar.height
                md_bg_color: app.theme_cls.primary_light

                MDLabel:
                    text: "Screen 1"
                    halign: "center"

            LabelMDScreen:
                name: "scr 2"

        MDNavigationDrawer:
            id: nav_drawer

            ContentNavigationDrawer:
                screen_manager: screen_manager
                nav_drawer: nav_drawer
'''


class ContentNavigationDrawer(MDBoxLayout):
    screen_manager = ObjectProperty()
    nav_drawer = ObjectProperty()


class TestNavigationDrawer(MDApp):
   
def build(self):
       
return Builder.load_string(KV)

   
def on_start(self):
       
print(f'{self =}')
       
print(f'{MDApp.get_running_app() =}')
       
print(f'{self.root.ids = }')
       
print(f'{self.root.ids.screen_manager =}')
       
print(f'{self.root.ids.screen_manager.get_screen("scr 2") =}')
       
print(f'{self.root.ids.screen_manager.get_screen("scr 2").ids =}')
       
print(f'{self.root.ids.screen_manager.get_screen("scr 2").ids.label =}')
       
print(f'{self.root.ids.screen_manager.get_screen("scr 2").ids.label.text =}')


TestNavigationDrawer().run()

Elias Coutinho

unread,
Mar 3, 2022, 3:24:38 PM3/3/22
to kivy-...@googlegroups.com
My friend Elliot, forgive my stupidity, my lack of knowledge but I am sending you a very minimalist example.

Could you return this example with the implementations?

I really couldn't.



from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import Screen

from kivymd.app import MDApp

KV = '''
<ContentNavigationDrawer>:

ScrollView:

MDList:

OneLineListItem:
text: "Screen 1"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 1"

OneLineListItem:
text: "Screen 2"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 2"


<MainScreen>:

MDToolbar:
id: toolbar
pos_hint: {"top": 1}
elevation: 10
title: "MDNavigationDrawer"
left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]

MDNavigationLayout:
x: toolbar.height

ScreenManager:
id: screen_manager

Screen:
name: "scr 1"

MDLabel:
text: "Put here the value of the user variable available in screen_login"
halign: "center"

Screen:
name: "scr 2"

MDLabel:
text: "Screen 2"
halign: "center"

MDNavigationDrawer:
id: nav_drawer

ContentNavigationDrawer:
screen_manager: screen_manager
nav_drawer: nav_drawer

<TelaLogin>:
name: 'screen_login'
md_bg_color: app.theme_cls.primary_color

MDLabel:
text: "Here I would login. and has a variable called user. The value of this variable must be read from anywhere in the application."
halign: "center"

MDFlatButton:
pos_hint: {'center_x': .5, 'center_y': .3}
text: 'Simulating correct login'
md_bg_color: 1, 0, 1, 1
on_release: root.login()

MDFlatButton:
pos_hint: {'center_x': .5, 'center_y': .2}
text: "MDFLATBUTTON"
md_bg_color: 1, 0, 1, 1
on_release: app.root.current = 'screen_singup'

<TelaSingUp>:
name: 'screen_signup'

MDLabel:
text: "merely owns nothing"
halign: "center"


ScreenManager:
id: screen_manager_login:
TelaLogin:
name: 'screen_login'
MainScreen:
name: 'main'

TelaSingUp:
name: 'screen_singup'
'''



class ContentNavigationDrawer(BoxLayout):
screen_manager = ObjectProperty()
nav_drawer = ObjectProperty()

class MainScreen(Screen):
pass

class TelaLogin(Screen):
def login(self):
user = 'Helo im user'
self.manager.current = 'main'


class TelaSingUp(Screen):
pass

class TestNavigationDrawer(MDApp):
def build(self):
return Builder.load_string(KV)


TestNavigationDrawer().run()


Elliot Garbus

unread,
Mar 3, 2022, 4:54:38 PM3/3/22
to kivy-...@googlegroups.com

Here is one way to do it, using a kivy property, called user.

 

from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import Screen
from kivy.properties import StringProperty

'''
                    text: app.user

                    halign: "center"
               

            Screen:
                name: "scr 2"

                MDLabel:
                    text: "Screen 2"
                    halign: "center"

        MDNavigationDrawer:
            id: nav_drawer

            ContentNavigationDrawer:
                screen_manager: screen_manager
                nav_drawer: nav_drawer

<TelaLogin>:
    name: 'screen_login'
    md_bg_color: app.theme_cls.primary_color

    # MDLabel:
    #     text: "Here I would login. and has a variable called user. The value of this variable must be read from anywhere in the application."
    #     halign: "center"
   
    MDTextField:
        hint_text: 'Enter User Name'
        on_text: app.user = self.text
(MDApp):
    user = StringProperty()

   
def build(self):
       
return Builder.load_string(KV)


TestNavigationDrawer().run()

Elliot Garbus

unread,
Mar 3, 2022, 5:00:49 PM3/3/22
to kivy-...@googlegroups.com

Here is another way to do it writing directly to the kivy property.

 

'''
                    id: user

                    halign: "center"
               

            Screen:
                name: "scr 2"

                MDLabel:
                    text: "Screen 2"
                    halign: "center"

        MDNavigationDrawer:
            id: nav_drawer

            ContentNavigationDrawer:
                screen_manager: screen_manager
                nav_drawer: nav_drawer

<TelaLogin>:
    name: 'screen_login'
    md_bg_color: app.theme_cls.primary_color

    # MDLabel:
    #     text: "Here I would login. and has a variable called user. The value of this variable must be read from anywhere in the application."
    #     halign: "center"
   
    MDTextField:
        hint_text: 'Enter User Name'
        on_text: app.root.get_screen('main').ids.user.text = self.text
(MDApp):

   
def build(self):
       
return Builder.load_string(KV)


TestNavigationDrawer().run()
1F99B0B8DD364ED29BDD75C57FC49620.png

Elliot Garbus

unread,
Mar 3, 2022, 5:25:10 PM3/3/22
to kivy-...@googlegroups.com

And a third way to do it, moving the string property to the main screen.

 

'''
                    id: user
                    halign: "center"
                    text: root.user

               

            Screen:
                name: "scr 2"

                MDLabel:
                    text: "Screen 2"
                    halign: "center"

        MDNavigationDrawer:
            id: nav_drawer

            ContentNavigationDrawer:
                screen_manager: screen_manager
                nav_drawer: nav_drawer

<TelaLogin>:
    name: 'screen_login'
    md_bg_color: app.theme_cls.primary_color

    # MDLabel:
    #     text: "Here I would login. and has a variable called user. The value of this variable must be read from anywhere in the application."
    #     halign: "center"
   
    MDTextField:
        id: user_name
        hint_text: 'Enter User Name'



    MDFlatButton:
        pos_hint: {'center_x': .5, 'center_y': .3}
        text: 'Simulating correct login'
        md_bg_color: 1, 0, 1, 1
        on_release:
            root.manager.get_screen('main').user = user_name.text 

            root.login()

    MDFlatButton:
        pos_hint: {'center_x': .5, 'center_y': .2}
        text: "MDFLATBUTTON"
        md_bg_color: 1, 0, 1, 1
        on_release: app.root.current = 'screen_singup'

<TelaSingUp>:
    name: 'screen_signup'

    MDLabel:
        text: "merely owns nothing"
        halign: "center"

ScreenManager:
    id: screen_manager_login

    TelaLogin:
        name: 'screen_login'

    MainScreen:
        name: 'main' 

    TelaSingUp:
        name: 'screen_singup'               
'''


class ContentNavigationDrawer(BoxLayout):
    screen_manager = ObjectProperty()
    nav_drawer = ObjectProperty()


class MainScreen
(Screen):
    user = StringProperty()


class TelaLogin(Screen):
   
def login(self):
       
self.manager.current = 'main'


class TelaSingUp(Screen):
   
pass


class
TestNavigationDrawer(MDApp):

   
def build(self):
       
return
Builder.load_string(KV)

   
def on_start(self):
       
print(MDApp.get_running_app().root)


TestNavigationDrawer().run()

Elias Coutinho

unread,
Mar 3, 2022, 5:26:10 PM3/3/22
to kivy-...@googlegroups.com
I tried as you asked and verified that my need is related to the python code, even so I tested from your guidance.
I received a return of None, the value does not appear.

However, I followed this same logic in the python codes and got the error below:

      print(MDApp.user, '----------')
  AttributeError: type object 'MDApp' has no attribute 'user'

--------------------------------------------------------------------------------------------

class ScreenInicio(Screen):
print(MDApp.user, '----------')


class TelaLogin(Screen):
def login(self):
MDApp.user = 'Helo im user'
#user = 'Helo im user'
self.manager.current = 'main'

class TestNavigationDrawer(MDApp):
user = StringProperty()
def build(self):
return Builder.load_string(KV)

Elias Coutinho

unread,
Mar 3, 2022, 8:07:49 PM3/3/22
to kivy-...@googlegroups.com
I want to thank you for the patience you always show for those who learn more slowly!

It was cool, I'll translate to my code now.


Elliot Garbus

unread,
Mar 3, 2022, 8:19:28 PM3/3/22
to kivy-...@googlegroups.com
You’re very welcome. Happy to help. 

Sent from my iPhone

On Mar 3, 2022, at 6:07 PM, Elias Coutinho <coutinh...@gmail.com> wrote:



Elias Coutinho

unread,
Mar 13, 2022, 10:31:07 AM3/13/22
to kivy-...@googlegroups.com
Elliot and friends, once again I apologize for insisting and not having understood your explanations but would it be possible to make adjustments to my gist below?

My Gist

I would like to modify the md_bg_color property of this widget <ElementCard@MDCard> line 205 from the MDApp in the color function at the snag of line 72.

Note: This code is missing imports and some screens on purpose to make it more fluent for your understanding.

Elliot Garbus

unread,
Mar 13, 2022, 11:04:28 AM3/13/22
to kivy-...@googlegroups.com

Line 205 is the kv rule definition of the ElementCard class.  You need to identify the instance of the class that you want to change.

 

Lets assume a app structure as follows:

 

RootWidget

    ScreenManager

        Id: sm

        Screen:

            name: ‘card_screen’

            BoxLayout:

                ElementCard:  # this is an instance of the ElementCard class, defined by the kv rule.

                    id: ec

                     

 

You would access the ElementCard Instance, ec from a method in App as:

 

def app_method(self)

    card = self.root.ids.sm.get_screen(‘card_screen’).ids.ec

 

The key thing to think about is you want to modify an instance – not the rule.  You need to address the instance of the class you want to modify.

 

I am unable to run the project.

Elias Coutinho

unread,
Mar 13, 2022, 1:53:45 PM3/13/22
to kivy-...@googlegroups.com
Sometimes I got this error, that is, with your help, I was on the right track.
This time was no different, I applied the order of the widgets in the two ways below and received the returns respectively:

Thus:
self.root.ids.sm.get_screen('main').ids.screen_manager.get_screen('new_screen').ids.ec.theme_cls.primary_dark

I received the response below:
     self.root.ids.sm.get_screen('main').ids.screen_manager.get_screen('new_screen').ids.ec.theme_cls.primary_dark
   File "kivy/properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'

-------------------------------------------------- -------------------------------------------------- ----


Already in this way:
self.root.ids.sm.get_screen('main').ids.screen_manager.get_screen('new_screen').ids.ec.md_bg_color = MDApp.theme_cls.primary_dark

I received the response below:
          self.root.ids.sm.get_screen('main').ids.screen_manager.get_screen('new_screen').ids.ec.md_bg_color = MDApp.theme_cls.primary_dark
 AttributeError: 'kivy.properties.ObjectProperty' object has no attribute 'primary_dark'

I tested it like this just to see if it would work but the second error explained that ObjectProperty doesn't have the attribute.

Hehehe I'm already very ashamed my brother!

Elliot Garbus

unread,
Mar 13, 2022, 2:07:25 PM3/13/22
to kivy-...@googlegroups.com

MDApp.theme_cls.primary_dark

This syntax would only work if theme_cls is a class level attribute vs an instance attribute.  I have not looked to see how it is implemented, but I suspect it is an instance level attribute.

 

Inside an MDApp method use:

self.theme_cls.primary_dark

 

In other classes…

app = MDApp.get_running_add()

app.theme_cls. primary_dark

 

To debug this issue:

Thus:
self.root.ids.sm.get_screen('main').ids.screen_manager.get_screen('new_screen').ids.ec.theme_cls.primary_dark

I received the response below:
     self.root.ids.sm.get_screen('main').ids.screen_manager.get_screen('new_screen').ids.ec.theme_cls.primary_dark
   File "kivy/properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'

print out each part the “kv string” to make sure it is what you expect.

print(self.root.ids)

print(self.root.ids.sm)

print(self.root.ids.sm.get_screen('main'))

print(self.root.ids.sm.get_screen('main').ids)

print(self.root.ids.sm.get_screen('main').ids.screen_manager) …

 

If the ids dict is empty it can mean that your are executing this code prior to the kv code being processed.  This will happen if you are accessing the ids in a __init__ method.  If this is the case move the code to an on_kv_post() method.

Elias Coutinho

unread,
Mar 13, 2022, 4:17:09 PM3/13/22
to kivy-...@googlegroups.com
I think the class that inherits from MDApp doesn't have the on_kv_post method.

Elliot Garbus

unread,
Mar 13, 2022, 5:46:47 PM3/13/22
to kivy-...@googlegroups.com
Correct, use on_start

Sent from my iPhone

On Mar 13, 2022, at 1:17 PM, Elias Coutinho <coutinh...@gmail.com> wrote:



Elias Coutinho

unread,
Mar 14, 2022, 8:53:04 AM3/14/22
to kivy-...@googlegroups.com
same error as before.

Elliot Garbus

unread,
Mar 14, 2022, 10:04:39 AM3/14/22
to kivy-...@googlegroups.com
Share your code. 

Sent from my iPhone

On Mar 14, 2022, at 5:53 AM, Elias Coutinho <coutinh...@gmail.com> wrote:



Elias Coutinho

unread,
Mar 14, 2022, 3:22:27 PM3/14/22
to kivy-...@googlegroups.com

Elliot Garbus

unread,
Mar 14, 2022, 8:26:59 PM3/14/22
to kivy-...@googlegroups.com

Here is the key problem your root widget is a ScreenManager, self.root is the screenmanger, you need to start there.

 

def on_start(self):
   
print(self.root.get_screen('main').ids.screen_manager.get_screen('nova_tela').ids.rv2)
   
self.root.get_screen('main').ids.screen_manager.get_screen('nova_tela').ids.rv2.md_bg_color = self.theme_cls.primary_dark

 

 

The code above will run, but I don’t expect it will do what you want because the Recycle view does not have a md_bg_color property.  The RecycleBoxLayout does not have the property either.  I’m assuming you want to create a background color for the RecycleBoxLayout.  You will need create a canvas and fill in the background with the canvas using Rectangle. 

Elias Coutinho

unread,
Mar 14, 2022, 8:41:17 PM3/14/22
to kivy-...@googlegroups.com
Dude you are really good!

Elliot Garbus

unread,
Mar 14, 2022, 8:43:04 PM3/14/22
to kivy-...@googlegroups.com

Thank you!

This is why I suggest printing out each step along the way…  when you print self.root, you can see it is the screenmanager.

Reply all
Reply to author
Forward
0 new messages