Python Kivy 如何将 Python 制作的小部件注入 kv 文件中的布局

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

我写了一个 python kivy 应用程序来显示测量值。在 kivy 上搜索内容时,我偶然发现了 kivy-md(Material Design for kivy)项目。我发现 UI 非常好看。这就是为什么我想将我的应用程序注入 kivy-md 项目的屏幕。

我的项目在文件夹 kivy-playground 中,其中包含 kivymd 文件夹中的文件 kivymdmain.py(用于启动 kivy md 应用程序)、 main.kv 文件(用于 kivy md 应用程序的布局)和一个 playground.py 其中包含用于显示测量值的 kivy 应用程序。我正在使用 Python 3.7 和最新版本的 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.

我试图编写一个最小的工作示例。这是文件

# 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()

这里是 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"

这里是 playground.py,我想将其注入主应用程序的屏幕 page2

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()

如果你能把Playground.py改成这样:

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()

然后,在您的 main.py 中,您可以添加:

from playGround import getPlaygroundRoot

然后使用add_widget(getPlaygroundRoot())Playground根添加到MainApp中的某个容器。

或者,如果您想在 .kv 文件中使用 Playground,您可以添加 #:import playground playGround 到您的 .kv 文件,然后添加:

        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)

将其添加到您的 page2

  • 如果有kv文件,playground.kv for playground.py then use include <file>main.kv
  • 添加导入语句,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.

片段

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: