Search code examples
pythonuser-interfacekivywidgetscreen

How do I switch screens in kivy?


I am currently having an issue in my code where I am unable to switch screens. Before I explain what the issue is specifically, I will include a snippet of my code below.

From main.py

import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen

Window.clearcolor = 255 / 255, 255 / 255, 255 / 255, 1
Window.size = 414, 736

sm = ScreenManager()

class PulseWelcome(Screen):
    pass

    class PulseWelcomeCanvas(Widget):
        pass

class PulseLogin(Screen):

    class PulseLoginCanvas(Widget):
        pass

class WindowManager(ScreenManager):
    pass

sm.add_widget(PulseWelcome(name = 'welcome'))
sm.add_widget(PulseLogin(name = 'login'))

class PulseApp(App):
    def build(self):
        return PulseWelcome()

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

From Pulse.kv

    #:kivy 2.1.0

WindowManager:
    PulseWelcome:
    PulseLogin:

<PulseWelcome>:

    id: welcome

    PulseWelcomeCanvas:

        Label:
            font_size: 30  
            font_name: 'assets/fonts/tommy.ttf'
            center_x: root.width / 2
            center_y: root.height / 2
            text: "Welcome to Pulse!"
            color: 0, 0, 0, 1

        Button:
            background_normal: 'assets/images/next_purple_normal.png'
            background_down: 'assets/images/next_purple_down.png'
            border: 0, 0, 0, 0
            center_x: root.width / 2
            center_y: 90
            height: 40
            width: 100
            on_press:
                root.manager.transition.direction = 'left'
                root.manager.current = 'login'

<PulseLogin>:

    id: login

    PulseLoginCanvas:

        Label:
            font_size: 30
            font_name: 'assets/fonts/tommy.ttf'
            text: 'Sign In or Sign Up'
            color: 0, 0, 0, 1
            center_x: root.width / 2
            center_y: root.height / 2

My app runs as it should when the program is started, however, when I click on my button in order to change screens I am presented with this error:

File "C:\Users\Nitro\Documents\Pulse\pulse.kv", line 30, in <module>
 root.manager.transition.direction = 'left'
 AttributeError: 'NoneType' object has no attribute 'transition'

I have tried a variety of solutions with no progress. My guess is that because I am trying to switch screens from a widget inside my screen class I am given the earlier discussed error. I originally decided to put a widget inside each screen class to organize elements because when I had tried to organize elements in the .kv file for the screen class independently (PulseWelcome, etc.) I had gui issues.

I also had tried defining a function in the screen class that could be activated through the contained widget. After trying that I was given this error:

kivy.uix.screenmanager.ScreenManagerException: ScreenManager accepts only Screen widget.

Not sure if anyone out there knows what may be causing the issue and how to fix it but if anyone has any sort of input for any of the issues previously mentioned all help is greatly appreciated.


Solution

  • You have not initialized the screenmanager you returning the screen and not the screenmanager

    main.py:

    import kivy
    from kivy.app import App
    from kivy.uix.widget import Widget
    from kivy.core.window import Window
    from kivy.uix.screenmanager import ScreenManager, Screen
    
    Window.clearcolor = 255 / 255, 255 / 255, 255 / 255, 1
    Window.size = 414, 736
    
    class PulseWelcome(Screen):
        pass
    
        class PulseWelcomeCanvas(Widget):
            pass
    
    class PulseLogin(Screen):
    
        class PulseLoginCanvas(Widget):
            pass
    
    class WindowManager(ScreenManager):
        pass
    
    
    class PulseApp(App):
        def build(self):
            sm = ScreenManager()
            sm.add_widget(PulseWelcome(name='welcome'))
            sm.add_widget(PulseLogin(name='login'))
            return sm
    
    if __name__ == '__main__':
        PulseApp().run()
    

    defining the build function like this should do the trick.

    .kv:

    <PulseWelcome>:
        id: welcome
        PulseWelcomeCanvas:
            Label:
                font_size: 30
                font_name: 'assets/fonts/tommy.ttf'
                center_x: root.width / 2
                center_y: root.height / 2
                text: "Welcome to Pulse!"
                color: 0, 0, 0, 1
            Button:
                background_normal: 'assets/images/next_purple_normal.png'
                background_down: 'assets/images/next_purple_down.png'
                border: 0, 0, 0, 0
                center_x: root.width / 2
                center_y: 90
                height: 40
                width: 100
                on_press:
                    root.manager.transition.direction = 'left'
                    root.manager.current = 'login'
    <PulseLogin>:
    
        id: login
    
        PulseLoginCanvas:
    
            Label:
                font_size: 30
                font_name: 'assets/fonts/tommy.ttf'
                text: 'Sign In or Sign Up'
                color: 0, 0, 0, 1
                center_x: root.width / 2
                center_y: root.height / 2
    

    I have also removed the screenmanager from the kv file as that wouldn't function when creating the screenmanger like I have done here. Otherwise you would have to create the build function like this

    build:

    def build:
        returm WindowManager()
    

    I have run in to some trouble with doing the build function like that so for now I would do it the way I first showed you

    Hope this helps