简体   繁体   中英

Python Kivy How to inject widgets made with Python to layout in kv file

I have written a python kivy application for displaying measurements. While searching stuff on kivy I stumbled on the the kivy-md (Material Design for kivy) project. I find the UI very good looking. That is why I want to inject my app into a screen of the kivy-md project.

My project is inside a folder kivy-playground which contains the kivymd files in a folder kivymd , the main.py (for starting the kivy md application), the main.kv file (for the layout of the kivy md application) and a playground.py which contains the kivy application for displaying measurements. I am using Python 3.7 with the latest version of kivy.

Goal : I want to inject the Application view from playground.py into the main application which is started by the main.py such that the view of the playground.py is displayed on the screen page2 (see main.kv ) of the main application. I am totally lost how this can be achieved and I would be happy if someone could show me on this toy example how this can be achieved. It is not necessarily important that the playground.py stays as it is. If the problem can be solved by small changes in the playground.py file then this would be also a valid solution.

I tried to cook up a minimal working example. Here are the files

# main.py
# -*- coding: utf-8 -*-

import os

from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivymd.theming import ThemeManager


class MainApp(App):

    theme_cls = ThemeManager()

    def __init__(self, **kwargs):
        super(MainApp, self).__init__(**kwargs)
        Window.bind(on_close=self.on_stop)

    def build(self):
        main_widget = Builder.load_file(
            os.path.join(os.path.dirname(__file__), "./main.kv")
        )
        self.theme_cls.theme_style = 'Dark'
        return main_widget

    def close_app(self, *largs):
        super(MainApp, self).stop(*largs)

    def on_pause(self):
        return True


if __name__ == '__main__':
    MainApp().run()

here is the main.kv

# main.kv
#:kivy 1.10.1
#:import Toolbar kivymd.toolbar.Toolbar
#:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer
#:import NavigationLayout kivymd.navigationdrawer.NavigationLayout
#:import NavigationDrawerToolbar kivymd.navigationdrawer.NavigationDrawerToolbar

NavigationLayout:
    id: nav_layout
    MDNavigationDrawer:
        id: nav_drawer
        NavigationDrawerToolbar:
        NavigationDrawerIconButton:
            icon: 'checkbox-blank-circle'
            text: "Page1"
            on_release: app.root.ids.scr_mngr.current = 'page1'
        NavigationDrawerIconButton:
            icon: 'checkbox-blank-circle'
            text: "Page2"
            on_release: app.root.ids.scr_mngr.current = 'page2'
    BoxLayout:
        orientation: 'vertical'
        halign: "center"
        Toolbar:
            id: toolbar
            md_bg_color: app.theme_cls.primary_color
            background_palette: 'Primary'
            background_hue: '500'
            right_action_items: [['dots-vertical', lambda x: app.root.toggle_nav_drawer()]]
        ScreenManager:
            id: scr_mngr
            Screen:
                name: 'page1'
                Label:
                    text: "page1"
            Screen:
                name: 'page2'
                Label:
                    text: "Page 2"

and here is the playground.py which I want to inject into the screen page2 of the main application.

from kivy.app import App
from kivy.uix.label import Label


class Playground(App):

    def build(self):
        hello_world_label = Label(text="Hello World!")
        return hello_world_label


if __name__ == "__main__":
    Playground().run()

If you can change Playground.py to something like this:

from kivy.app import App
from kivy.uix.label import Label

def getPlaygroundRoot():
    hello_world_label = Label(text="Hello World!")
    return hello_world_label


class PlayGround(FloatLayout):
    def __init__(self, **kwargs):
        super(PlayGround, self).__init__(**kwargs)
        self.add_widget(getPlaygroundRoot())

class Playground(App):

    def build(self):
        return getPlaygroundRoot()


if __name__ == "__main__":
    Playground().run()

Then, in your main.py , you can add:

from playGround import getPlaygroundRoot

And then use add_widget(getPlaygroundRoot()) to add the Playground root to some container in the MainApp .

Or, if you want to use Playground in your .kv file, you can add #:import playground playGround to your .kv file, and then add:

        Screen:
            name: 'page2'
            Label:
                text: "Page 2"
                pos_hint: {'center_x': 0.5, 'y': 0.8}
                size_hint: (1.0, 0.2)
            PlayGround:
                pos_hint: {'center_x': 0.5, 'y': 0.1}
                size_hint: (1.0, 0.2)

to add it to your page2 .

  • If there is a kv file, playground.kv for playground.py then use include <file> in main.kv
  • Add import statement, from playground import PlayGround in main.py

Kivy Lang Directives » include <file>

 include <file> 

Syntax:

 #:include [force] <file> 

Includes an external kivy file. This allows you to split complex widgets into their own files. If the include is forced, the file will first be unloaded and then reloaded again.

Snippets

playground.py

from kivy.app import App
from kivy.uix.label import Label


class PlayGround(Label):
    pass


class Playground(App):

    def build(self):
        return PlayGround()


if __name__ == "__main__":
    Playground().run()

playground.kv

#:kivy 1.11.0

<PlayGround>:
    text: "Hello World!"

min.py

# main.py
# -*- coding: utf-8 -*-

import os

from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivymd.theming import ThemeManager
from playground import PlayGround


class MainApp(App):

main.kv

# main.kv
#:kivy 1.10.1
#:import Toolbar kivymd.toolbar.Toolbar
#:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer
#:import NavigationLayout kivymd.navigationdrawer.NavigationLayout
#:import NavigationDrawerToolbar kivymd.navigationdrawer.NavigationDrawerToolbar

#:include playground.kv

NavigationLayout:
    ...
        ScreenManager:
            id: scr_mngr
            Screen:
                name: 'page1'
                Label:
                    text: "page1"
            Screen:
                name: 'page2'
                Label:
                    text: "Page 2"
                PlayGround:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM