Search code examples
pythonpython-3.xkivykivy-languagekivymd

How to update KivyMD Nav Drawer after a user login?


I want to update the ContentNavigationDrawer which displays the user photo and email but I can't seem to access the ids.

In the login.py code below, you can see the code that I tried to use to update the content drawer with a simple button. What am I missing?

Main.py

from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.app import MDApp
from test_login import LoginScreen

Window.size = (440, 760)
kv = '''
<ContentNavigationDrawer>:
    id: content_nav
    orientation: "vertical"
    AnchorLayout:
        anchor_x: "center"
        size_hint_y: None
        height: 100
        FitImage:
            id: user_photo
            radius: [50,]
            size_hint: None, None
            size: 100,100
            source: 'data/assets/img/profile_photo_placeholder.jpg'
    MDLabel:
        id: user_email
        text: "--"
        halign: "center"
        font_style: "Button"
        size_hint_y: None
        height: self.texture_size[1]
    ScrollView:
        MDList:
            OneLineIconListItem:
                text: 'Login'
                on_release:
                    root.nav_drawer.set_state("close")
                    root.screen_manager.current = "go_to_login"
Screen:
    MDToolbar:
        id: toolbar
        pos_hint: {"top": 1}
        left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]

    MDNavigationLayout:
        x: toolbar.height
        ScreenManager:
            id: screen_manager
            Screen:
                name: "words_nav_item"
            LoginScreen:
                name: "go_to_login"

        MDNavigationDrawer:
            id: nav_drawer
            ContentNavigationDrawer:
                screen_manager: screen_manager
                nav_drawer: nav_drawer

'''
class ContentNavigationDrawer(BoxLayout):
    pass

class main_test(MDApp):
    def build(self):
        self.content = ContentNavigationDrawer()
        self.kv = Builder.load_string(kv)
        return self.kv

main_test().run()

Login.py

from kivy.app import App
from kivy.lang import Builder
from kivymd.uix.screen import MDScreen

kv = '''
<LoginScreen>:
    MDGridLayout:
        cols: 1
        padding: [50,40,50,0]
        MDGridLayout:
            cols: 1
            size_hint: 1, None
            height: 240
            padding: [0,0,0,20]
            AnchorLayout:
                anchor_x: 'center'
                anchor_x: 'center'
                anchor_y: 'center'
                MDRectangleFlatButton:
                    text: "Update User Profile "
                    on_release:
                        root.update_user_profile()

'''

class LoginScreen(MDScreen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.app = App.get_running_app()
        Builder.load_string(kv)

    def update_user_profile(self):
        user_photo = "data/img/profile.png"
        user_email = "[email protected]"

        #NOT WORKING
        #self.app.content.ids.user_email.text = user_email

        # NOT WORKING
        #self.app.kv.ids.user_email.text = user_email

        # WORKING
        self.app.kv.ids.toolbar.pos_hint= {"top": .5}

Solution

  • In the build() method of your App, the line:

    self.content = ContentNavigationDrawer()
    

    is creating a new instance of ContentNavigationDrawer, but this new instance is not the instance that appears in your GUI. You need to get a reference to the actual instance of ContentNavigationDrawer that is in you GUI. To do that, you can add another id in your kv:

        MDNavigationDrawer:
            id: nav_drawer
            ContentNavigationDrawer:
                id: content  # new id to access this instance
                screen_manager: screen_manager
                nav_drawer: nav_drawer
    

    Then you can use this new id in your build() method:

    class main_test(MDApp):
        def build(self):
            # self.content = ContentNavigationDrawer()
            self.kv = Builder.load_string(kv)
            self.content = self.kv.ids.content
            return self.kv
    

    Then, in your update_user_profile() method, the line:

    self.app.content.ids.user_email.text = user_email
    

    should work. And the line:

    self.app.kv.ids.user_email.text = user_email
    

    can be modified to use the new id:

    self.app.kv.ids.content.ids.user_email.text = user_email