Search code examples
pythonpython-3.xkivykivy-languagekivymd

Why is switching screens not working in kivy?


I am trying to switch screens in kivy and I have been stuck on this for a while so I don't know what is going on. The text is being printed but the screen is still not changing. Here is the python code if anyone can help me out:

from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivymd.theming import ThemableBehavior
from kivymd.uix.list import MDList
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivymd.uix.button import MDFloatingBottomButton



Window.size = (300, 500)

class MainScreen(Screen):
    def switch_button(self):
        print("switching")
        ScreenManager.current = "FileScreen"  
        

class FileScreen(Screen):
    pass


class app(MDApp):
    data = {
        'Create': 'file-document',
        'Open': 'folder-open'
        
    }
    def btn(self, instance):
        print('callback')
        icon = instance.icon
        # if you want check button, use
        if isinstance(instance, MDFloatingBottomButton):

            if icon == 'file-document':
                print('Create')
                MainScreen.switch_button(self)
                
                
                
            elif icon == 'folder-open':
                print('Open')

    class ContentNavigationDrawer(BoxLayout):
        pass

    class DrawerList(ThemableBehavior, MDList):
        pass

        sm = ScreenManager()
        sm.add_widget(MainScreen(name='MainScreen'))
        sm.add_widget(FileScreen(name='FileScreen'))
        
    def build(self):
        self.theme_cls.primary_palette = "Red"
        #self.theme_cls.accent_palette = "Teal"
        screen = Builder.load_file("main.kv")
        return screen
        
        

    

app().run()

Here is the .KV code:

ScreenManager:
    MainScreen:
    FileScreen:
    
<MainScreen>:
    name: "MainScreen"
    MDFloatingActionButtonSpeedDial:
        bg_hint_color: app.theme_cls.primary_light
        data: app.data
        root_button_anim: True
        callback: app.btn

<FileScreen>:
    name: "FileScreen"
    MDBoxLayout:
        MDLabel:
            text: "test"

I hope the community can help me as soon as they can because if have been stuck on this for a while.


Solution

  • It appears that you are confusing classes and instances. In your switch_button() method your code:

    ScreenManager.current = "FileScreen"
    

    is setting the current attribute of the ScreenManager class, but the current property is an instance property and must be set on an instance of ScreenManager. And it must be the instance that is managing the FileScreen Screen.

    A better coding of the switch_button() method:

    class MainScreen(Screen):
        def switch_button(self):
            print("switching")
            self.manager.current = "FileScreen"
    

    The self.manager is a reference to the ScreenManager that is managing the MainScreen, which is also managing the FileScreen.

    Elsewhere, you are making a similar confusion between class and instance:

    MainScreen.switch_button(self)
    

    Again, you need the instance of MainScreen, not the MainScreen class. This line can be replaced by:

    self.root.get_screen('MainScreen').switch_button()
    

    This code uses the get_screen() method of ScreenManager to access the instance of MainScreen, then calls the instance method switch_button().

    A more direct approach would be to replace that line with:

    self.root.current = 'FileScreen'