Kivy: изменение экранов в диспетчере экрана с помощью пресс-мероприятия

Я хотел бы знать, как изменить экраны с помощью события on_press, привязанного к кнопке, без использования языка KV-файла/KV.

Я прочитал документацию Kivy, но смог найти решения только с помощью файла KV.

пример:

on_press: root.manager.current = 'screen2'

Я также могу изменить экран в главном файле python, используя:

screenmanager.current = 'screen2'

но я не могу понять, как добиться того же с помощью кнопки.

3 ответов


один простой способ сделать это, чтобы определить свой собственный подкласс кнопки:

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

метод on_press автоматически вызывается при нажатии кнопки, поэтому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)

это будет означать, что switching_function вызывается всякий раз, когда some_button нажата. Конечно, здесь есть много гибкости в отношении того, как и когда вы определяете функцию, поэтому (например) вы можете сделать что-то более общее, например, передать screenmanager в качестве первого аргумента функции.

Я не тестировал этот код, и это не полное приложение, но, надеюсь, смысл ясен. Любой из методов должен работать нормально, вы можете выбрать способ, которым кажется, это разумно. Я мог бы построить более полный пример позже.


рабочий пример с двумя экранами, нет 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()

другим решением было использовать setter метод EventDispatcher, чтобы получить ссылку на функцию setter для screen_manager.ток

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

конечно, это не очень сексуально, поэтому kv часто является более чистым решением для этих вещей, но он должен работать.

PS: в случае, если вы не знаете об этом!--2--> происходит от functools module, и часто полезно создавать такие обратные вызовы с предварительно загруженным параметром.