Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kivy: Changing screens in screen manager with an on_press event

Tags:

python

kivy

I would like to know how to change screens using an on_press event binded to a button, without using a KV file/KV language.

I have read through the Kivy documentation, but have only been able to find solutions using a KV file.

Example:

on_press: root.manager.current = 'screen2'

I can also change the screen in the main python file using:

screenmanager.current = 'screen2'

But I cant figure out how to achieve the same using a button.

like image 978
Derick Avatar asked Oct 21 '13 09:10

Derick


3 Answers

A working example with two screens, no kv file everything done in Python:

import kivy
kivy.require('1.8.0')

from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager 
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import ObjectProperty

class ScreenOne(Screen):

    def __init__ (self,**kwargs):
        super (ScreenOne, self).__init__(**kwargs)

        my_box1 = BoxLayout(orientation='vertical')
        my_label1 = Label(text="BlaBlaBla on screen 1", font_size='24dp')
        my_button1 = Button(text="Go to screen 2",size_hint_y=None, size_y=100)
        my_button1.bind(on_press=self.changer)
        my_box1.add_widget(my_label1)
        my_box1.add_widget(my_button1)
        self.add_widget(my_box1)

    def changer(self,*args):
        self.manager.current = 'screen2'

class ScreenTwo(Screen):

    def __init__(self,**kwargs):
        super (ScreenTwo,self).__init__(**kwargs)

        my_box1 = BoxLayout(orientation='vertical')
        my_label1 = Label(text="BlaBlaBla on screen 2",font_size='24dp')
        my_button1 = Button(text="Go to screen 1",size_hint_y=None, size_y=100)
        my_button1.bind(on_press=self.changer)
        my_box1.add_widget(my_label1)
        my_box1.add_widget(my_button1)
        self.add_widget(my_box1)

    def changer(self,*args):
        self.manager.current = 'screen1'

class TestApp(App):

        def build(self):
            my_screenmanager = ScreenManager()
            screen1 = ScreenOne(name='screen1')
            screen2 = ScreenTwo(name='screen2')
            my_screenmanager.add_widget(screen1)
            my_screenmanager.add_widget(screen2)
            return my_screenmanager

if __name__ == '__main__':
    TestApp().run()
like image 163
TomKivy Avatar answered Oct 23 '22 00:10

TomKivy


Another solution, was to use the setter method of EventDispatcher, to get a reference to the setter function for screen_manager.current

button.bind(on_press=partial(sm.setter('current'), (sm, 'whatever'))

of course, it's not very sexy, that's why kv is often a cleaner solution to these things, but it should work.

ps: in case you don't know about it, partial comes from the functools module, and it's often useful to build these kind of callbacks with a preloaded parameter.

like image 26
Tshirtman Avatar answered Oct 23 '22 01:10

Tshirtman


One simple way to accomplish this is to define your own button subclass:

class ScreenButton(Button):
    screenmanager = ObjectProperty()
    def on_press(self, *args):
        super(ScreenButton, self).on_press(*args)
        self.screenmanager.current = 'whatever'

The on_press method is automatically called when the button is pressed, so the screenmanager's current property will be changed.

Then you can have code something like:

sm = ScreenManager()

sc1 = Screen(name='firstscreen')
sc1.add_widget(ScreenButton(screenmanager=sm))

sc2 = Screen(name='whatever')
sc2.add_widget(Label(text='another screen'))

sm.add_widget(sc1)
sm.add_widget(sc2)

Clicking the button should switch the screens as required.

Another way (which is probably how kv language actually does it) would be to manually use the bind method.

def switching_function(*args):
    some_screen_manager.current = 'whatever'

some_button.bind(on_press=switching_function)

This would mean that switching_function is called whenever some_button is pressed. Of course there is a lot of flexibility here regarding how and when you define the function, so (for instance) you could do something more general like pass the screenmanager as the first argument to the function.

I didn't test this code and it isn't a complete app, but hopefully the meaning is clear. Either method should work fine, you can choose the way that seems most sensible. I might construct a more complete example later.

like image 20
inclement Avatar answered Oct 23 '22 02:10

inclement