Search code examples
pythonkivykivy-languagekivymd

How do I get KivyMD Navigation Drawer to call another app in a separate .py file?


I know how to write an app with kivy and I understand how to make a KivyMD app that has a navigation drawer. I can make the apps run individually but how do I combine the two?

I am new to coding and I am stuck here. Below are the codes for two mock-up apps for training purposes only. The first is a very simple app called "+5 Game" that allows the user to click a button to add 5 to the total which is then displayed in the GUI.

The second is a KivyMD app with a navigation drawer that contains two buttons. One to go to the home screen and one to go to the "+5 Game"

How do I link the button in the navigation draw to the +5 game? And what do I do about the imports at the top of the file?

This is the code for the +5 Game:

from kivymd.app import MDApp
from kivymd.uix.screen import Screen
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDRectangleFlatButton


class ClickToAdd(MDApp):
    def build(self):
        self.screen = Screen()
        self.num = 0

        self.display_number = MDLabel(text="0", font_style="H1", halign="center",
                                      pos_hint={'center_x': 0.5, 'center_y': 0.8})
        self.add5_BTN = MDRectangleFlatButton(text="+5", pos_hint={'center_x': 0.5, 'center_y': 0.65},
                                              on_release=self.add5_CMD)

        self.screen.add_widget(self.display_number)
        self.screen.add_widget(self.add5_BTN)

        return self.screen

    def add5_CMD(self, *args):
        self.num = self.num + 5
        self.display_number.text = str(self.num)


ClickToAdd().run()

This is the main GUI of the KivyMD app with a navigation drawer and a screen manager:

from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivymd.app import MDApp

KV = '''
<ContentNavigationDrawer>:
    ScrollView:
        MDList:
            OneLineListItem:
                text: "Home"
                on_press:
                    root.nav_drawer.set_state("close")
                    root.screen_manager.current = "home"

            OneLineListItem:
                text: "Play +5 Game"
                on_press:
                    root.nav_drawer.set_state("close")
                    root.screen_manager.current = "plus5game"


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

    MDNavigationLayout:
        x: toolbar.height
        ScreenManager:
            id: screen_manager
            Screen:
                name: "home"
                MDLabel:
                    text: "Home Screen Stuff Goes Here"
                    halign: "center"

            Screen:
                name: "plus5game"
                MDLabel:
                    text: "+5 Game Goes here"
                    halign: "center"

        MDNavigationDrawer:
            id: nav_drawer

            ContentNavigationDrawer:
                screen_manager: screen_manager
                nav_drawer: nav_drawer
'''


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


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


TestNavigationDrawer().run()

Solution

  • You cannot run one App inside another App, but you can use the guts of another App inside the first. In your case, you can redefine the the Plus5 App like this:

    from kivymd.app import MDApp
    from kivymd.uix.screen import Screen
    from kivymd.uix.label import MDLabel
    from kivymd.uix.button import MDRectangleFlatButton
    
    class Plus5Screen(Screen):
        def __init__(self, **kwargs):
            super(Plus5Screen, self).__init__(**kwargs)
            self.num = 0
    
            self.display_number = MDLabel(text="0", font_style="H1", halign="center",
                                          pos_hint={'center_x': 0.5, 'center_y': 0.8})
            self.add5_BTN = MDRectangleFlatButton(text="+5", pos_hint={'center_x': 0.5, 'center_y': 0.65},
                                                  on_release=self.add5_CMD)
    
            self.add_widget(self.display_number)
            self.add_widget(self.add5_BTN)
    
        def add5_CMD(self, *args):
            self.num = self.num + 5
            self.display_number.text = str(self.num)
    
    
    class ClickToAdd(MDApp):
        def build(self):
            self.screen = Plus5Screen()
            return self.screen
    
    if __name__=='__main__':
        ClickToAdd().run()
    

    and save this is a file named plus5.py.

    Then in you main App, you can just reference this in the 'kv':

    KV = '''
    #:import Plus5Screen plus5   # import the guts of the Plus5 game
    <ContentNavigationDrawer>:
        ScrollView:
            MDList:
                OneLineListItem:
                    text: "Home"
                    on_press:
                        root.nav_drawer.set_state("close")
                        root.screen_manager.current = "home"
    
                OneLineListItem:
                    text: "Play +5 Game"
                    on_press:
                        root.nav_drawer.set_state("close")
                        root.screen_manager.current = "plus5game"
    
    
    Screen:
        MDToolbar:
            id: toolbar
            pos_hint: {"top": 1}
            elevation: 10
            title: "Navigation Drawer Test"
            left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
    
        MDNavigationLayout:
            x: toolbar.height
            ScreenManager:
                id: screen_manager
                Screen:
                    name: "home"
                    MDLabel:
                        text: "Home Screen Stuff Goes Here"
                        halign: "center"
    
                Plus5Screen:  # this creates the guts of the Plu5 game
                    name: "plus5game"
    
            MDNavigationDrawer:
                id: nav_drawer
    
                ContentNavigationDrawer:
                    screen_manager: screen_manager
                    nav_drawer: nav_drawer
    '''