Home > Enterprise >  Kivy Nested ScreenManager inside BoxLayout
Kivy Nested ScreenManager inside BoxLayout

Time:01-07

Something seen with a different flavor each week, Here we go again with more ScreenManager shenanigans!

Screens won't change unless buttons are part of the screen itself, I wanted a universal navbar along the top and then a "display" under it. Both screens work, the buttons to switch between them don't.

(Bonus points if you can tell me how to make each screen its own KV file and still link with the screenmanager)

anyways: CODE

QCManager.py

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

kivy.require('1.9.1')


class MOTD(Screen):
    print("MOTD Screen!")
    pass


class Search(Screen):
    print("Search Screen!")
    pass


class ScreenManagement(ScreenManager):
    pass


class ClassAllScreen(BoxLayout):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.manager = ScreenManagement()


class ClassApp(App):

    def build(self):
        self.root = ClassAllScreen()
        return self.root

if __name__ == '__main__':
    Builder.load_file('./kvfiles/main.kv')
    ClassApp().run()

main.kv

#: import NoTransition kivy.uix.screenmanager.NoTransition
<MOTD>:
    name: 'motd'
    BoxLayout:
        orientation:'vertical'
        padding:20
        spacing:10
        Label:
            text:"The Cake Is a Lie"

<Search>:
    name: 'search'
    BoxLayout:
        orientation:'vertical'
        padding:20
        spacing:10
        GridLayout:
            spacing:10
            cols:2

            Button:
                text:'Left'
            Button:
                text:'Right'
        Button:
            text:'bottom'


<ScreenManagement>:
    transition: NoTransition()
    MOTD:
    Search:

<ClassAllScreen>:
    orientation:'vertical'
    BoxLayout:
        size_hint_y: None
        height: 60
        spacing: 5
        padding: 5

        canvas:
            Color:
                rgba: .1,.1,.1,1
            Rectangle:
                pos: self.pos
                size: self.size
        Button:
            text:'Menu'
            size_hint_x: None
            width: 120
            on_release: root.manager.current = 'motd'
        Button:
            text:'Search'
            size_hint_x: None
            width: 120
            on_release: root.manager.current = 'search'
        Button:
            text:'Add to DB'
            size_hint_x: None
            width: 120
            on_press: print("Button Working")
    ScreenManagement:

CodePudding user response:

You __init__() method in the ClassAllScreen class is creating an instance of ScreenManagement. That instance is saved as self.manager, but is not added to your GUI.

In your kv file, the line:

ScreenManagement:

is creating another, different instance of ScreenManagement. This instance of ScreenManagement is the one that is in your GUI.

So anything your do to self.manager in the ClassAllScreen will have no effect on the ScreenManagement that is in your GUI.

The fix is to make sure you are referencing the correct instance of ScreenManagement (and not bother to create any other instances). To do this you can add an ObjectProperty to ClassAllScreen in the kv file, like this:

<ClassAllScreen>:
    manager: scr_manager  # added ObjectProperty that references the scr_manager id
    orientation:'vertical'
    BoxLayout:
        size_hint_y: None
        height: 60
        spacing: 5
        padding: 5

        canvas:
            Color:
                rgba: .1,.1,.1,1
            Rectangle:
                pos: self.pos
                size: self.size
        Button:
            text:'Menu'
            size_hint_x: None
            width: 120
            on_release: root.manager.current = 'motd'
        Button:
            text:'Search'
            size_hint_x: None
            width: 120
            on_release: root.manager.current = 'search'
        Button:
            text:'Add to DB'
            size_hint_x: None
            width: 120
            on_press: print("Button Working")
    ScreenManagement:
        id: scr_manager  # new id to enable reference to this ScreenManagement instance

And the ClassAllScreen class can then be simplified to:

class ClassAllScreen(BoxLayout):
    pass

CodePudding user response:

Just to help out anyone trying to do the same. The fixed code is below

App.py

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

kivy.require('1.9.1')


class MOTD(Screen):
    print("MOTD Screen!")
    pass


class Search(Screen):
    print("Search Screen!")
    pass


# class ScreenManagement(ScreenManager):
    # pass  # Removed, Instanced in kv


class ClassAllScreen(BoxLayout):
    pass  # Removed code, Done in kv


class ClassApp(App):
    def build(self):
        self.root = ClassAllScreen()
        return self.root

if __name__ == '__main__':
    Builder.load_file('./kvfiles/main.kv')
    ClassApp().run()

main.kv

#: import NoTransition kivy.uix.screenmanager.NoTransition
<MOTD>:
    name: 'motd'
    BoxLayout:
        orientation:'vertical'
        padding:20
        spacing:10
        Label:
            text:"The Cake Is a Lie"

<Search>:
    name: 'search'
    BoxLayout:
        orientation:'vertical'
        padding:20
        spacing:10
        GridLayout:
            spacing:10
            cols:2

            Button:
                text:'Left'
            Button:
                text:'Right'
        Button:
            text:'bottom'


<ClassAllScreen>:
    manager:scr_manager
    orientation:'vertical'
    BoxLayout:
        size_hint_y: None
        height: 60
        spacing: 5
        padding: 5

        canvas:
            Color:
                rgba: .1,.1,.1,1
            Rectangle:
                pos: self.pos
                size: self.size
        Button:
            text:'Menu'
            size_hint_x: None
            width: 120
            on_release: root.manager.current = 'motd'
        Button:
            text:'Search'
            size_hint_x: None
            width: 120
            on_release: root.manager.current = 'search'
        Button:
            text:'Add to DB'
            size_hint_x: None
            width: 120
            on_press: print("Button Working")
    ScreenManager:
        transition: NoTransition()
        id: scr_manager
        MOTD:
        Search:
  •  Tags:  
  • Related