Kivy - Kv - ScreenManager - 改变当前屏幕

Posted

技术标签:

【中文标题】Kivy - Kv - ScreenManager - 改变当前屏幕【英文标题】:Kivy - Kv - ScreenManager - changing the current screen 【发布时间】:2018-05-25 20:18:50 【问题描述】:

我正在尝试在kivy(kv)中做一个非常简单的例子如下:

#:import Toolbar kivymd.toolbar.Toolbar

BoxLayout:
    orientation: 'vertical'
    Toolbar:
        id: toolbar
        title: 'My Toolbar'
        md_bg_color: app.theme_cls.primary_color
        background_palette: 'Primary'
        background_hue: '500'
        left_action_items: [['arrow-left', app.root.ids.scr_mngr.current = 'screen1' ]]
        right_action_items: [['arrow-right', app.root.ids.scr_mngr.current = 'screen2' ]]
    ScreenManager:
        id: scr_mngr
        Screen:
            name: 'screen1'
            Toolbar:
                title: "Screen 1"
        Screen:
            name: 'screen2'
            Toolbar:
                title: "Screen 2"

这将失败,因为 left_action_items 和 right_action_items 都需要一个对列表:[name_of_icon, expression]。另一方面,当您处理按钮时,该语句将是合法的,例如,如果我们执行以下操作:

on_release:
    app.root.ids.scr_mngr.current = 'screen1'

另一方面,left_action_item 的正确方法是:

left_action_items: [['arrow-left', lambda x: app.root.ids.scr_mngr.current = 'screen1' ]]

但是这是不合法的,因为你不能在 python 下的 lambda 中执行这样的赋值。

left_action_items 改变屏幕的正确方法是什么?

【问题讨论】:

【参考方案1】:

这是我发现点击 MDToolbar 图标更改屏幕的最简单方法:

ma​​in.py

from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.lang import Builder

Builder.load_file("telas.kv")


class Tela1(Screen):
    pass


class Tela2(Screen):
    pass


class MainApp(MDApp):
    def build(self):
        self.sm = ScreenManager(transition=NoTransition())
        self.sm.add_widget(Tela1(name="tela1"))
        self.sm.add_widget(Tela2(name="tela2"))
        return self.sm

    def change_screen(self, tela):
        self.sm.current = tela

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

telas.kv

<Tela1>:
    BoxLayout:
        orientation: "vertical"
        MDToolbar:
            title: "My App"
        MDRoundFlatButton:
            text: "Go to Tela 2"
            on_release: app.root.current = "tela2"
        MDLabel:
            text: "Tela 1"

<Tela2>:
    BoxLayout:
        orientation: "vertical"
        MDToolbar:
            title: "Tela 2"
            left_action_items: [["arrow-left",  lambda x: app.change_screen("tela1")]]
        MDLabel:
            text: "Tela 2"

【讨论】:

【参考方案2】:

你可以把你的根类变成一个 python 类,并在那里有一个 change_screen 方法。还将您的屏幕管理器设置为根类中的 ObjectProperty。 然后在 kv 中使用 partial 以便能够将参数传递给方法。 试试这样:

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivymd.theming import ThemeManager

class MyLayout(BoxLayout):

    scr_mngr = ObjectProperty(None)

    def change_screen(self, screen, *args):
        self.scr_mngr.current = screen


KV = """
#:import Toolbar kivymd.toolbar.Toolbar
#:import partial functools.partial

MyLayout:
    scr_mngr: scr_mngr
    orientation: 'vertical'
    Toolbar:
        id: toolbar
        title: 'My Toolbar'
        left_action_items: [['arrow-left', partial(root.change_screen, 'screen1') ]]
        right_action_items: [['arrow-right', partial(root.change_screen, 'screen2') ]]
    ScreenManager:
        id: scr_mngr
        Screen:
            name: 'screen1'
            Toolbar:
                title: "Screen 1"
        Screen:
            name: 'screen2'
            Toolbar:
                title: "Screen 2"
"""


class MyApp(App):
    theme_cls = ThemeManager()

    def build(self):
        return Builder.load_string(KV)


MyApp().run()

【讨论】:

它有效。遗憾的是,ScreenManager 没有提供执行以下操作的可能性: set_screen('screen1')【参考方案3】:

有多种选择,你可以做

left_action_items: [('arrow-left', (app.root.ids.scr_mngr, 'current', 'screen1'))]

然后再做:

for icon, expr in self.left_action_items:
    setattr(*expr)

如果你真的想要一个可执行的表达式,你可以这样做:

left_action_items: [('arrow-left', lambda: setattr(app.root.ids.scr_mngr, 'current' 'screen1'))]

【讨论】:

【参考方案4】:

还有一种方法。我使用的:

left_action_items: [['arrow-left', lambda x: root.manager.change_screen("main_screen")]]

屏幕管理器内部函数change_screen()的实现:

def change_screen(self, screen):
    # the same as in .kv: app.root.current = screen
    self.current = screen

【讨论】:

以上是关于Kivy - Kv - ScreenManager - 改变当前屏幕的主要内容,如果未能解决你的问题,请参考以下文章

如何:main.py,带有 kivy 轮播代码的新类,kv 文件

使用按钮更改 kivy 或 kivymd 中的屏幕

kivy:全局变量和 ScreenManager

Kivy 无法使用 ScreenManager 获取文本输入

Kivy ScreenManager 打破 BoxLayout

在 Kivy 1.10 和 Python 2.7.9 中使用 ScreenManager 获取 TextInput 值