Phil Penny
Phil Penny

Reputation: 123

Python Kivy screen manager wiget scope

I am trying to control a screen manager from buttons in a separate class, but I cannot figure out what to set on the button on_press: statements.

Kivy Python Nav

Kivy file:

<HeaderSection>:
    anchor_x: 'center'
    anchor_y: 'top'
    BoxLayout:
        orientation: 'horizontal'
        size_hint: 1, .1
        id: header
        Label:
            text: 'My App'

<ContentSection>:
    anchor_x: 'center'
    anchor_y: 'center'
    ScreenManager:
        size_hint: 1, .8
        Screen:
            name: 'home'
            Label:
                text: 'First screen'
        Screen:
            name: 'second'
            Label:
                text: 'Second screen'
        Screen:
            name: 'third'
            Label:
                text: 'Third screen'

<FooterSection>:
    anchor_x: 'center'
    anchor_y: 'bottom'
    BoxLayout:
        orientation: 'horizontal'
        size_hint: 1, .1
        Button:
            text: 'first'
            on_press: root.ContentSection.manager.current = 'first'
        Button:
            text: 'second'
            on_press: root.current = 'second'
        Button:
            text: 'third'
            on_press: ContentSection.ScreenManager.current = 'third'

Python file:

from kivy.app import App
from kivy.lang import Builder
Builder.load_file('MyApp.kv')
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.uix.image import Image

# Declare sections
class HeaderSection(AnchorLayout):
    pass

class ContentSection(AnchorLayout):
    def build(self):

        # Create the screen manager
        sm = ScreenManager()
        sm.add_widget(FirstScreen(name='first'))
        sm.add_widget(SecondScreen(name='second'))
        sm.add_widget(ThirdScreen(name='third'))
        return sm

class FooterSection(AnchorLayout):
    pass


class MyAppApp(App):
    def build(self):

        #Create the sections

        fl = FloatLayout()
        hs = HeaderSection()
        cs = ContentSection()
        fs = FooterSection()

        fl.add_widget(hs)
        fl.add_widget(cs)
        fl.add_widget(fs)
        return fl


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

I have tried various methods:

on_press: root.parent.ContentSection.ScreenManager.current = 'home'
on_press: root.parent.ContentSection.manager.current = 'home'
on_press: root.ContentSection.manager.current = 'home'

I feel like it is a scoping issue, errors say things like:

AttributeError: 'FooterSection' object has no attribute 'ContentSection'

So my app has the following hierarchy:

FloatLayout
    HeaderSection
    ContentSection
        ScreenManager
             FirstScreen
             SecondScreen
             ThirdScreen
    FooterSection
        Button for FirstScreen
        Button for SecondScreen
        Button for ThirdScreen

So I need to traverse up a level into FloatLayout, then drill down into ContentSection to access the screen manager.

Upvotes: 0

Views: 1496

Answers (1)

ebuenger
ebuenger

Reputation: 11

Navigating widget trees has been a pain for me, and AFAIK you can't traverse the widget tree the way you'd like.

You can, however, simplify your widget tree, make sure everything shares the same root, and use ids.

Here's how I did it (I also moved everything to kv language):

kv

FloatLayout:
    AnchorLayout:
        anchor_x: 'center'
        anchor_y: 'top'
        Label:
            size_hint: 1, .1
            text: 'My App'
    AnchorLayout:
        anchor_x: 'center'
        anchor_y: 'center'
        ScreenManager:
            id: manager
            size_hint: 1, .8
            Screen:
                name: 'first'
                Label:
                    text: 'First screen'
            Screen:
                name: 'second'
                Label:
                    text: 'Second screen'
            Screen:
                name: 'third'
                Label:
                    text: 'Third screen'
    AnchorLayout:
        anchor_x: 'center'
        anchor_y: 'bottom'
        BoxLayout:
            orientation: 'horizontal'
            size_hint: 1, .1
            Button:
                text: 'first'
                on_press: root.ids.manager.current = 'first'
            Button:
                text: 'second'
                on_press: root.ids.manager.current = 'second'
            Button:
                text: 'third'
                on_press: root.ids.manager.current = 'third'

python

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.uix.image import Image



class MyAppApp(App):
    def build(self):
        return Builder.load_file('MyApp.kv')


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

Upvotes: 1

Related Questions