mantielero
mantielero

Reputation: 79

Kivy - Kv - ScreenManager - changing the current screen

I am trying to do a very simple example in kivy (kv) as follows:

#: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"

This will fail because both left_action_items and right_action_items expect a list of pairs: [name_of_icon, expression]. On the other hand, when you deal with buttons, the statement would be legal for instance if we do something like:

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

On the other hand, the right approach for left_action_item would be something like:

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

But this is not legal, because you cannot perform such assigment in lambda under python.

What would be right approach for left_action_items to change the screen?

Upvotes: 1

Views: 5655

Answers (4)

Márcio Moreira
Márcio Moreira

Reputation: 505

This is the simplest way I have found to change the screen clicking on a MDToolbar icon:

main.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"

Upvotes: 3

Maxim Kravchenko
Maxim Kravchenko

Reputation: 434

Also one more method. That I using:

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

Realization of function change_screen() inside the screen manager:

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

Upvotes: 2

Matt
Matt

Reputation: 1347

There are multiple options, you can do

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

and later do:

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

If you really want an executable expression you can do:

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

Upvotes: 2

el3ien
el3ien

Reputation: 5405

You could make your root class into a python class, and have a change_screen method there. Also make your screenmanager to an ObjectProperty in the root class.
Then use partial in kv to be able to pass arguments to the method.
Try like this:

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

Upvotes: 2

Related Questions