简体   繁体   English

Kivy:通过on_press事件更改屏幕管理器中的屏幕

[英]Kivy: Changing screens in screen manager with an on_press event

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. 我想知道如何使用绑定到按钮的on_press事件来更改屏幕,而不使用KV文件/ KV语言。

I have read through the Kivy documentation, but have only been able to find solutions using a KV file. 我已阅读过Kivy文档,但只能使用KV文件查找解决方案。

Example: 例:

on_press: root.manager.current = 'screen2'

I can also change the screen in the main python file using: 我也可以使用以下命令在主python文件中更改屏幕:

screenmanager.current = 'screen2'

But I cant figure out how to achieve the same using a button. 但是我不知道如何使用按钮来实现相同的目的。

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. 按下按钮时会自动调用on_press方法,因此将更改屏幕管理器的current属性。

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. 另一种方法(这可能是kv语言实际上是如何做到的)将是手动使用bind方法。

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. 这意味着switching_function每当被称为some_button被按下。 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. 当然,在定义函数的方式和时间方面,这里有很多灵活性,因此(例如)您可以做一些更通用的事情,例如将screenmanager传递给函数的第一个参数。

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. 以后我可能会构建一个更完整的示例。

A working example with two screens, no kv file everything done in Python: 一个有两个屏幕的工作示例,没有kv文件,所有在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()

Another solution, was to use the setter method of EventDispatcher, to get a reference to the setter function for screen_manager.current 另一种解决方案是使用EventDispatcher的setter方法,以获得对screen_manager.current的setter函数的引用。

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. 当然,它不是很性感,这就是为什么kv通常可以更干净地解决这些问题,但它应该可以工作。

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. ps:如果您不了解它, partial来自functools模块,并且使用预加载的参数构建此类回调通常很有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM