Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

kivy - How to Update KivyMD Label in the first screen with on_enter function?

Give below is the kivyMD screen manager program from https://github.com/attreyabhatt/KivyMD-Basics/blob/master/13%20-%20Switching%20Screens/main.py

and I have added it to the official navigation drawer program https://kivymd.readthedocs.io/en/latest/components/navigation-drawer/index.html of KivyMD.

This program works perfectly, but I want to change the text in the MenuScreen with the on_enter function. I have commented the def on_enter inside class MenuScreen. If we run it uncommented shows this error:

 Traceback (most recent call last):
   File "kivyproperties.pyx", line 861, in kivy.properties.ObservableDict.__getattr__
 KeyError: 'label_id'
 
 During handling of the above exception, another exception occurred:
 
 Traceback (most recent call last):
   File "C:/Users/Administrator/PycharmProjects/kivy_prj1/kivy_mainmd/nav_screen.py", line 170, in <module>
     sm.add_widget(MenuScreen(name='menu'))
   File "C:UsersAdministratorpyenvlt_kivyvirtlibsite-packageskivyuixscreenmanager.py", line 997, in add_widget
     self.current = screen.name
   File "kivyproperties.pyx", line 498, in kivy.properties.Property.__set__
   File "kivyproperties.pyx", line 545, in kivy.properties.Property.set
   File "kivyproperties.pyx", line 600, in kivy.properties.Property.dispatch
   File "kivy\_event.pyx", line 1248, in kivy._event.EventObservers.dispatch
   File "kivy\_event.pyx", line 1154, in kivy._event.EventObservers._dispatch
   File "C:UsersAdministratorpyenvlt_kivyvirtlibsite-packageskivyuixscreenmanager.py", line 1062, in on_current
     screen.dispatch('on_enter')
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:/Users/Administrator/PycharmProjects/kivy_prj1/kivy_mainmd/nav_screen.py", line 156, in on_enter
     self.ids.label_id.text = "Label text Updated"
   File "kivyproperties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'

'label_id' is the id of my label that is to be changed.

from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, ListProperty

from kivymd.app import MDApp
from kivymd.theming import ThemableBehavior
from kivymd.uix.list import OneLineIconListItem, MDList
from kivy.uix.screenmanager import ScreenManager, Screen

KV = '''
# Menu item in the DrawerList list.
<ItemDrawer>:
    theme_text_color: "Custom"
    on_release: self.parent.set_color_item(self)

    IconLeftWidget:
        id: icon
        icon: root.icon
        theme_text_color: "Custom"
        text_color: root.text_color


<ContentNavigationDrawer>:
    orientation: "vertical"
    padding: "8dp"
    spacing: "8dp"

    AnchorLayout:
        anchor_x: "left"
        size_hint_y: None
        height: avatar.height

        Image:
            id: avatar
            size_hint: None, None
            size: "56dp", "56dp"
            source: "data/logo/kivy-icon-256.png"

    MDLabel:
        text: "KivyMD library"
        font_style: "Button"
        size_hint_y: None
        height: self.texture_size[1]

    MDLabel:
        text: "kivydevelopment@gmail.com"
        font_style: "Caption"
        size_hint_y: None
        height: self.texture_size[1]

    ScrollView:

        DrawerList:
            id: md_list



Screen:
    ScreenManager:
        MenuScreen:
        ProfileScreen:
        UploadScreen:

    NavigationLayout:

        ScreenManager:

            Screen:

                BoxLayout:
                    orientation: 'vertical'

                    MDToolbar:
                        title: "Navigation Drawer"
                        elevation: 10
                        left_action_items: [['menu', lambda x: nav_drawer.toggle_nav_drawer()]]

                    Widget:


        MDNavigationDrawer:
            id: nav_drawer

            ContentNavigationDrawer:
                id: content_drawer


<MenuScreen>:
    name: 'menu'
    MDRectangleFlatButton:
        text: 'Profile'
        pos_hint: {'center_x':0.5,'center_y':0.6}
        on_press: root.manager.current = 'profile'
    MDRectangleFlatButton:
        text: 'Upload'
        pos_hint: {'center_x':0.5,'center_y':0.5}
        on_press: root.manager.current = 'upload'
    MDLabel:
        id:label_id
        text: 'update this at on enter'
        pos_hint: {'center_x':0.5,'center_y':0.4}
        halign: 'center'
    
<ProfileScreen>:
    name: 'profile'
    MDLabel:
        text: 'Profile'
        halign: 'center'
    MDRectangleFlatButton:
        text: 'Back'
        pos_hint: {'center_x':0.5,'center_y':0.1}
        on_press: root.manager.current = 'menu'
        
<UploadScreen>:
    name: 'upload'
    MDLabel:
        text: 'Upload'
        halign: 'center'
    MDRectangleFlatButton:
        text: 'Back'
        pos_hint: {'center_x':0.5,'center_y':0.1}
        on_press: root.manager.current = 'menu'
'''


class ContentNavigationDrawer(BoxLayout):
    pass


class ItemDrawer(OneLineIconListItem):
    icon = StringProperty()
    text_color = ListProperty((0, 0, 0, 1))


"""Instead of just giving MDList in kv file give DrawerList for adding the ThemableBehavior with it and created color 
changing fn """


class DrawerList(ThemableBehavior, MDList):
    def set_color_item(self, instance_item):
        """Called when tap on a menu item."""

        # Set the color of the icon and text for the menu item.
        for item in self.children:
            if item.text_color == self.theme_cls.primary_color:
                item.text_color = self.theme_cls.text_color
                break
        instance_item.text_color = self.theme_cls.primary_color
        # print(f"inst:{instance_item.text_color}", f"thm_txt{self.theme_cls.text_color}",
        #       f"thm_prm{self.theme_cls.primary_color}")


class MenuScreen(Screen):
    pass
    # def on_enter(self, *args):
    #     self.ids.label_id.text = "Label text Updated"


class ProfileScreen(Screen):
    pass



class UploadScreen(Screen):
    pass


# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(ProfileScreen(name='profile'))
sm.add_widget(UploadScreen(name='upload'))


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

    def on_start(self):
        icons_item = {
            "folder": "My files",
            "account-multiple": "Shared with me",
            "star": "Starred",
            "history": "Recent",
            "checkbox-marked": "Shared with me",
            "upload": "Upload",
        }
        for icon_name in icons_item.keys():
            self.root.ids.content_drawer.ids.md_list.add_widget(
                ItemDrawer(icon=icon_name, text=icons_item[icon_name])
            )


TestNavigationDrawer().run()

So anybody knows how to change the first screens label or anything from on_enter in KivyMD? Note: Uncomment the # def on_enter(self, *args): # self.ids.label_id.text = "Label text Updated" this. It will show the error.

question from:https://stackoverflow.com/questions/65856208/how-to-update-kivymd-label-in-the-first-screen-with-on-enter-function

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I haven't exactly find an answer, but found a way around(have to run app somehow).

Step 1: Remove these lines:

sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(ProfileScreen(name='profile'))
sm.add_widget(UploadScreen(name='upload'))

edit the kv-program like this:

Screen:
    ScreenManager:
        MenuScreen:
            name:"menu"
        ProfileScreen:
            name:"profile"
        UploadScreen:
            name:"upload"

You can use self.parent.current = "screen_name" inside any Screen manager class in the python program instead of sm.current = "screen_name. And if you needed to change screen inside of a layout which is inside of other and so.. instead of using self.parent.parent... you can use MDApp.get_running_app().root.ids.screen_manger.current = "screen_name"

Step2: To avoid on_enter problem for the first screen create a logo screen that show up only at the start of application like this:

Add this in python program

class HomeScreen(Screen):
    pass

and edit Kv-program like this:

Screen:
    ScreenManager:
        HomeScreen:
            name:"home"
        MenuScreen:
            name:"menu"
        ProfileScreen:
            name:"profile"
        UploadScreen:
            name:"upload"

and add this to the kv-program

<HomeScreen>:
    BoxLayout:
    Button:
        size:self.size
        on_press:
            root.manager.current = "menu"

You can add image or animation on the button.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...