Austin
Austin

Reputation: 335

(Kivy Python) Switching Screens on Button Press Inside .py file

I understand that it is relatively easy to switch screens in the .kv file using on_release. I want to keep my button creating in the .py file, however, so I do not want to use this method. I have done the following to add a function that occurs when the 14th button is pressed. When the button is pressed in the program nothing happens. Experimenting with other names for the screen to sm.current to threw the error: "kivy.uix.screenmanager.ScreenManagerException: No Screen with name "InputScreen" when the 14th button was pressed."

# Kivy Formatting
kv_text='''\

<MyScreenManager>:
    LandingScreen:
    InputScreen:

<InputScreen@Screen>:
    name: 'input_sc'
    AnchorLayout:
        id: anchor_1

<LandingScreen@Screen>:
    name: 'landing_sc'
    GridLayout:
        id: grid_1
        cols: 5
        height: 480
        width: 800
        spacing: 25, 20
        padding: 25,25

'''
# Screen Manager
class MyScreenManager(ScreenManager):
    pass

# Main screen with button layout
class LandingScreen(Screen):
    def __init__(self, **kwargs):
        super(LandingScreen, self).__init__(**kwargs)
        self.buttons = [] # add references to all buttons here
        Clock.schedule_once(self._finish_init)

    # IDs have to be used here because they cannot be applied until widget initialized
    def _finish_init(self, dt):
        self.ids.grid_1.cols = 5

        # Loop to make 15 different buttons on screen
        for x in range(15):
            self.buttons.append(Button(text='button {}'.format(x)))
            self.ids.grid_1.add_widget(self.buttons[x])
            self.buttons[x].background_normal = 'YOUTUBE.png'

        def SwitchScreen(self,*args):
            sm.current = 'input_sc'

        sm = ScreenManager()
        sm.add_widget(InputScreen(name='input_sc'))
        sm.add_widget(LandingScreen(name='landing'))
        self.buttons[14].bind(on_release=SwitchScreen)


# Input screen
class InputScreen(Screen):
    pass

class MySubApp(App):
    def build(self):
        return MyScreenManager()

def main():
    Builder.load_string(kv_text)
    app = MySubApp()
    app.run()

if __name__ == '__main__':
    main()

If someone could help me understand the hole in my current logic I would appreciate it greatly. Thanks.

Upvotes: 1

Views: 1579

Answers (1)

FJSevilla
FJSevilla

Reputation: 4513

Each screen has a manager property that gives you the instance of the ScreenManager used. You only need to use it to refer to the ScreemManager instance and use its current method:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.clock import Clock


# Kivy Formatting
kv_text='''\

<MyScreenManager>:
    LandingScreen:
    InputScreen:

<InputScreen@Screen>:
    name: 'input_sc'
    AnchorLayout:
        id: anchor_1
        Button:
            text: 'Hello'

<LandingScreen@Screen>:
    name: 'landing_sc'
    GridLayout:
        id: grid_1
        cols: 5
        height: 480
        width: 800
        spacing: 25, 20
        padding: 25,25

'''
# Screen Manager
class MyScreenManager(ScreenManager):
    pass

# Main screen with button layout
class LandingScreen(Screen):
    def __init__(self, **kwargs):
        super(LandingScreen, self).__init__(**kwargs)
        self.buttons = [] # add references to all buttons here
        Clock.schedule_once(self._finish_init)

    # IDs have to be used here because they cannot be applied until widget initialized
    def _finish_init(self, dt):
        self.ids.grid_1.cols = 5

        # Loop to make 15 different buttons on screen
        for x in range(15):
            self.buttons.append(Button(text='button {}'.format(x)))
            self.ids.grid_1.add_widget(self.buttons[x])
            self.buttons[x].background_normal = 'YOUTUBE.png'

        self.buttons[14].bind(on_release=self.switch_screen)

    def switch_screen(self, *args):
        self.manager.current = 'input_sc'

# Input screen
class InputScreen(Screen):
    pass

class MySubApp(App):
    def build(self):
        return MyScreenManager()

def main():
    Builder.load_string(kv_text)
    app = MySubApp()
    app.run()

if __name__ == '__main__':
    main()

Upvotes: 3

Related Questions