【问题标题】:Kivy: Changing screens in screen manager with an on_press eventKivy:使用 on_press 事件在屏幕管理器中更改屏幕
【发布时间】:2013-10-29 18:06:06
【问题描述】:

我想知道如何使用绑定到按钮的 on_press 事件来更改屏幕,而不使用 KV 文件/KV 语言。

我已通读 Kivy 文档,但只能使用 KV 文件找到解决方案。

例子:

on_press: root.manager.current = 'screen2'

我还可以使用以下方法更改主 python 文件中的屏幕:

screenmanager.current = 'screen2'

但我不知道如何使用按钮来达到同样的效果。

【问题讨论】:

    标签: python kivy


    【解决方案1】:

    一个有两个屏幕的工作示例,没有 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()
    

    【讨论】:

    • 是否有特殊原因导致这不适用于 Kivy 1.9.2?
    【解决方案2】:

    实现此目的的一种简单方法是定义您自己的按钮子类:

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

    按下按钮时会自动调用on_press方法,所以screenmanager的current属性会发生变化。

    然后你可以有类似的代码:

    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)
    

    单击按钮应根据需要切换屏幕。

    另一种方式(这可能是 kv 语言的实际操作方式)是手动使用 bind 方法。

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

    这意味着只要按下some_button,就会调用switching_function。当然,关于如何以及何时定义函数,这里有很大的灵活性,因此(例如)您可以做一些更一般的事情,比如将屏幕管理器作为第一个参数传递给函数。

    我没有测试这段代码,它不是一个完整的应用程序,但希望含义清楚。任何一种方法都应该可以正常工作,您可以选择看起来最明智的方法。稍后我可能会构建一个更完整的示例。

    【讨论】:

    • 感谢您的回答。使用子类解决方案帮助我实现了我想要做的事情。再次感谢。
    【解决方案3】:

    另一种解决方案,是使用 EventDispatcher 的setter 方法,获取 screen_manager.current 的 setter 函数的引用

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

    当然,它不是很性感,这就是为什么 kv 通常是解决这些问题的更清洁的解决方案,但它应该可以工作。

    ps:如果您不知道,partial 来自 functools 模块,使用预加载参数构建此类回调通常很有用。

    【讨论】:

    • 我对 kivy 还很陌生,所以性感在我的名单上并不高。这对我来说非常方便。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-13
    相关资源
    最近更新 更多