将我的自定义小部件连接到我的屏幕管理器

connecting my custom widget to my screen manager

我正在尝试使用 Python 和 kivy 构建应用程序。 在我的 kv 文件中,我想创建一个自定义小部件 (MenuFloatLayout) 可以被其他屏幕引用。它基本上是每个屏幕上的菜单栏。此栏包含多个处于按下状态的切换按钮,如果您当前位于此按钮所在的屏幕上,则这些按钮将被禁用。linked。

引用者: 状态:"down" if root.manager.current == 'Screenname' else "normal"

问题是: root.manager.current 不再 linked 到通常的屏幕管理器, 因为我的自定义小部件现在是根。

有解决办法吗? 或者是否有更简单的方法 link 用户所在屏幕的切换按钮状态?

我是编程新手 Python,很高兴您能给我任何帮助或提示!谢谢!

Python 文件:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager


class StartWindow(Screen):
    pass


class PortfolioOverview(Screen):
    pass


class Portfolio(Screen):
    pass


class Market(Screen):
    pass


class Economics(Screen):
    pass


class PortfolioTools(Screen):
    pass


class WindowManager(ScreenManager):
    pass


kv = Builder.load_file("vigiles.kv")


class VigilesApp(App):
    def build(self):
        return kv


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

以及 kv 文件:

WindowManager:
    StartWindow:
    PortfolioOverview:
    Portfolio:
    Market:
    Economics:
    PortfolioTools:

<MenuFloatLayout@FloatLayout>:
    Label:
        text: "Portfolio"
        markup: True
        size_hint: 0.5, None
        height: 30
        pos_hint:{"top":1, "left":1}

    TextInput:
        text: "Search"
        multiline: False
        size_hint: 0.5, None
        height: 30
        pos_hint:{"top":1, "right":1}

    ScrollView:
        size_hint: None, None
        do_scroll_y: False
        do_scroll_x: True
        size: 500, 150

        GridLayout:
            rows: 1
            size_hint_y: None

            ToggleButton:
                group: "pmenu"
                text: 'Overview'
                state: "down" if root.manager.current == 'poverview' else "normal"
                disabled: True if root.manager.current == 'poverview' else False
                background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
                disabled_color: 1, 1, 1, 1
                on_release: app.root.current = "poverview"

            ToggleButton:
                group: "pmenu"
                text: 'Portfolio'
                state: "down" if root.manager.current == 'portfolio' else "normal"
                disabled: True if root.manager.current == 'portfolio' else False
                background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
                disabled_color: 1, 1, 1, 1
                on_release: app.root.current = "portfolio"

            ToggleButton:
                group: "pmenu"
                text: 'Market'
                state: "down" if root.manager.current == 'market' else "normal"
                disabled: True if root.manager.current == 'market' else False
                background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
                disabled_color: 1, 1, 1, 1
                on_release: app.root.current = "market"

            ToggleButton:
                group: "pmenu"
                text: 'Economics'
                state: "down" if root.manager.current == 'economics' else "normal"
                disabled: True if root.manager.current == 'economics' else False
                background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
                disabled_color: 1, 1, 1, 1
                on_release: app.root.current = "economics"

            ToggleButton:
                group: "pmenu"
                text: 'Tools'
                state: "down" if root.manager.current == 'ptools' else "normal"
                disabled: True if root.manager.current == 'ptools' else False
                background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
                disabled_color: 1, 1, 1, 1
                on_release: app.root.current = "ptools"


<StartWindow>:
    name: "start"
    BoxLayout:
        canvas:
            Rectangle:
                size: self.size
        color: 1, 1, 1, 0
        id: login_layout
        orientation: 'vertical'
        padding: [10,10,10,10]
        spacing: 30

        Label:
            text: 'some text'
            font_size: 32
            color: 0, 0, 0, 1

        BoxLayout:
            orientation: 'vertical'

            Label:
                text: 'Login'
                font_size: 18
                halign: 'left'
                text_size: root.width-20, 20
                color: 0, 0, 0, 1

            TextInput:
                id: login
                multiline:False
                font_size: 28

        BoxLayout:
            orientation: 'vertical'
            Label:
                text: 'Password'
                halign: 'left'
                font_size: 18
                text_size: root.width-20, 20
                color: 0, 0, 0, 1

            TextInput:
                id: password
                multiline:False
                password:True
                font_size: 28

        Button:
            text: 'Connect'
            font_size: 24
            on_release: app.root.current = "poverview"



<PortfolioOverview>:
    name: "poverview"
    MenuFloatLayout:

<Portfolio>:
    name: "portfolio"
    MenuFloatLayout:

<Market>:
    name: "market"
    MenuFloatLayout:

<Economics>:
    name: "economics"
    MenuFloatLayout:

<PortfolioTools>:
    name: "ptools"
    MenuFloatLayout:

目标是 link 我的自定义小部件返回到我的屏幕管理器,或者找到一个更简单的解决方案 link 切换按钮状态到当前屏幕。

AttributeError: 'MenuFloatLayout' 对象没有属性 'manager'

我会让您的根小部件成为布局小部件(GridLayoutBoxLayoutFloatLayout),并让您的屏幕管理器仅占用实际屏幕的一部分。尝试改变

WindowManager:
    StartWindow:
    PortfolioOverview:
    Portfolio:

至:

GridLayout:
    # Play with using a FloatLayout or BoxLayout instead of GridLayout if you want
    cols: 1
    MenuFloatLayout:
        id: the_menu_id
    WindowManager:
        StartWindow:
        PortfolioOverview:
        Portfolio:

这样你的菜单就会保留下来,屏幕管理器只会改变实际屏幕的一部分。

通过给 MenuFloatLayout 一个 id 你可以引用它。要从 Python 端引用它,如果您从 App 对象引用它,请使用 self.root.ids.the_menu_id。如果你在一些其他类型的对象中,你可以通过首先导入 App (import App) 然后使用 App.get_running_app().root.ids.the_menu_id

来做同样的事情

要从您的屏幕引用它,您可以使用 app 关键字。例如:app.root.ids.the_menu_id

引用菜单 id 的所有三种方式在本质上是相同的。

问题

  • MenuFloatLayout
  • 的实例过多
  • 使用大量资源,例如内存,这会使应用程序变大且性能不佳

解决方案

  • 创建一个 MenuFloatLayout
  • 实例
  • 每个屏幕引用 MenuFloatLayout
  • 的唯一一个实例
  • 使用嵌套ScreenManager。这第一个 ScreenManager 用于控制身份验证/登录屏幕。第二个 ScreenManager 用于不同屏幕之间的导航。
  • ToggleButton
  • 创建 dynamic class

例子

main.py

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager


class StartWindow(Screen):
    pass


class PortfolioOverview(Screen):
    pass


class Portfolio(Screen):
    pass


class Market(Screen):
    pass


class Economics(Screen):
    pass


class PortfolioTools(Screen):
    pass


class WindowManager(ScreenManager):
    pass


Builder.load_file("main.kv")


class TestApp(App):
    def build(self):
        return WindowManager()


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

main.kv - kv 文件

<WindowManager>:
    sm2: sm2
    StartWindow:
    Screen:
        name: 'connect'

        ScreenManager:
            id: sm2
            PortfolioOverview:
            Portfolio:
            Market:
            Economics:
            PortfolioTools:

        MenuFloatLayout:


<CustomToggleButton@ToggleButton>:    # dynamic class
    group: "pmenu"
    state: "normal" if app.root is None else "down" if app.root.sm2.current == self.text.lower() else "normal"

    background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
    disabled_color: 1, 1, 1, 1

    on_state:
        if self.state == "down": self.disabled = True
        else: self.disabled = False

    on_release:
        app.root.sm2.current = self.text.lower()


<MenuFloatLayout@FloatLayout>:    # dynamic class
    Label:
        text: "Portfolio"
        markup: True
        size_hint: 0.5, None
        height: 30
        pos_hint:{"top":1, "left":1}

    TextInput:
        hint_text: "Search"
        multiline: False
        size_hint: 0.5, None
        height: 30
        pos_hint:{"top":1, "right":1}

    ScrollView:
        size_hint: None, None
        do_scroll_y: False
        do_scroll_x: True
        size: 500, 150

        GridLayout:
            rows: 1
            size_hint_y: None

            CustomToggleButton:
                text: 'Overview'
                state: 'down'   # default

            CustomToggleButton:
                text: 'Portfolio'

            CustomToggleButton:
                text: 'Market'

            CustomToggleButton:
                text: 'Economics'

            CustomToggleButton:
                text: 'Tools'


<StartWindow>:
    name: "start"
    BoxLayout:
        canvas:
            Rectangle:
                size: self.size
        color: 1, 1, 1, 0
        id: login_layout
        orientation: 'vertical'
        padding: [10,10,10,10]
        spacing: 30

        Label:
            text: 'some text'
            font_size: 32
            color: 0, 0, 0, 1

        BoxLayout:
            orientation: 'vertical'

            Label:
                text: 'Login'
                font_size: 18
                halign: 'left'
                text_size: root.width-20, 20
                color: 0, 0, 0, 1

            TextInput:
                id: login
                multiline:False
                font_size: 28

        BoxLayout:
            orientation: 'vertical'
            Label:
                text: 'Password'
                halign: 'left'
                font_size: 18
                text_size: root.width-20, 20
                color: 0, 0, 0, 1

            TextInput:
                id: password
                multiline:False
                password:True
                font_size: 28

        Button:
            text: 'Connect'
            font_size: 24
            on_release:
                root.manager.current = 'connect'



<PortfolioOverview>:
    name: "overview"
    Label:
        text: 'Screen - Overview'

<Portfolio>:
    name: "portfolio"
    Label:
        text: 'Screen - Portfolio'

<Market>:
    name: "market"
    Label:
        text: 'Screen - Market'

<Economics>:
    name: "economics"
    Label:
        text: 'Screen - Economics'

<PortfolioTools>:
    name: "tools"
    Label:
        text: 'Screen - Portfolio Tools'

输出