0

问题:

如何在不使用 KV 语言的情况下使用 On-Press 事件更改 python 中动态创建的按钮的屏幕?

目标:

能够通过单击动态创建的按钮导航到新屏幕,

[不需要在 Kivy 中创建按钮,并且仍然可以在 Python 和 Kivy 中使用 Screenmanager(不确定您是否必须在整个程序中坚持使用 Python 或 Kivy?)

我已经尝试过的事情:

  1. 使用button_share.bind(on_press = self.changer),然后这个:

def changer(self,*args):
    ScreenManager()
    screenmanager.current = 'MainScreen'

但我得到了错误ScreenManagerException: No Screen with name "MainScreen".

怀疑:

我认为这是因为我正在创建一个 ScreenManager 的新实例,而不是引用现有的实例。为了解决这个问题,我考虑在 App 类中实例化 Screenmanager(),然后在我的按钮def changer(self, *args)方法中引用该实例化,但如果它不是我实际用于所有屏幕的 ScreenManager,那将毫无用处。这些都是用 KV 语言定义的。如果没有大量的努力,我将无法将它们全部切换。

  1. 使用:

button_share.bind(on_press=partial(app.sm.setter('current'), (app.sm, "MainScreen")))`

但我在这里得到的错误是ValueError: ScreenManager.current accept only str

下面是一个完全可运行的示例:

注意:在这个例子中,我想点击“继续编辑”按钮,然后点击“测试 1”、“测试 2”或“测试 3”按钮,让它带我到另一个屏幕。

蟒蛇代码:

from kivy.app import App
# kivy.require("1.10.0")
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.clock import Clock
from kivy.uix.widget import Widget
#from kivy.base import runTouchApp
from kivy.properties import StringProperty, ObjectProperty, NumericProperty
from functools import partial

class ScrollableLabelDataEntryInstructions(BoxLayout):
    pass

class NewGarageScreen(Screen):
    pass

class ContinueEditingScreen(Screen):
    pass

class GarageNameBoxLayout(BoxLayout):
    box_share2 = ObjectProperty()
    sm = ScreenManager()

    def __init__(self, **kwargs):
        super(GarageNameBoxLayout, self).__init__(**kwargs)
        self.orientation = "vertical"
        Clock.schedule_interval(self.create_button, 5)

    def create_button(self, *args):
        self.box_share2.clear_widgets()
        app = App.get_running_app()
        #put GarageNameStartList data into app class, then pull from it in this class
        top_button_share = 1.1
        color = (.4, .4, .4, 1)
        for i in range(len(app.GarageNameStartList)):
            top_button_share -= .4
            id_ = app.GarageNameStartList[i]

            button_share = Button(background_normal='',
                                  background_color = color,
                                  id = id_,
                                  pos_hint = {"x": 0, "top": top_button_share},
                                  size_hint_y = None,
                                  height = 60,
                                  font_size = 30,
                                  text = app.GarageNameStartList[i])
            button_share.bind(on_press = self.changer)
            #button_share.bind(on_press=partial(app.sm.setter('current'), (app.sm, "MainScreen")))
            self.box_share2.add_widget(button_share)

    def changer(self,*args):
        ScreenManager()
        #app = App.get_running_app()
        screenmanager.current = 'MainScreen'

class BackHomeWidget(Widget):
    pass

class MainScreen(Screen):
    pass

class AnotherScreen(Screen):
    pass

class ScreenManagement(ScreenManager):
    pass

presentation = Builder.load_file("example_on_press.kv")

class MainApp(App):
    GarageNameStartList = ["Test1", "Test2", "Test3"]

    def Update_GarageNameStartList(self, *args):
        self.GarageNameStartList = ["Test1", "Test2", "Test3"]   


    def build(self):
        return presentation

if __name__ == "__main__":
    MainApp().run()

千伏代码:

#: import FadeTransition kivy.uix.screenmanager.FadeTransition

ScreenManagement:
    transition: FadeTransition()
    MainScreen:
    AnotherScreen:
    NewGarageScreen:
    ContinueEditingScreen:

<SmallNavButton@Button>:    
    font_size: 32
    size: 125, 50    
    color: 0,1,0,1

<MedButton@Button>:
    font_size: 30
    size_hint: 0.25, 0.1
    color: 0,1,0,1

<BackHomeWidget>:
    SmallNavButton:
        on_release: app.root.current = "main"
        text: "Home"
        pos: root.x, root.top - self.height

<MainScreen>:
    name: "main"
    FloatLayout: 
        MedButton:
            on_release: app.root.current = "edit"
            text: "Edit"
            pos_hint: {"x":0.3728, "top": 0.4}

<AnotherScreen>:
    name: "edit"
    BackHomeWidget:
        SmallNavButton:
            on_release: app.root.current = "main"
            text: "Back"
            pos: root.x, root.top - (2.25*(self.height))
    FloatLayout:
        MedButton:
            on_release: app.root.current = "continueediting"
            text: "Continue Editing"
            pos_hint: {"x":0.25, "top": 0.6} 
        MedButton:
            on_release: app.root.current = "newgarage"
            text: "Create New"
            pos_hint: {"x":0.3728, "top": 0.4}

<NewGarageScreen>:
    name: "newgarage"
    BackHomeWidget:
        SmallNavButton:
            on_release: app.root.current = "edit"
            text: "Back"
            pos: root.x, root.top - (2.25*(self.height))
    FloatLayout:
        MedButton:
            text: "1. Groundfloor"
            pos_hint: {"x":0, "top": 0.6}


<GarageNameBoxLayout>:
    box_share2: box_share2
    ScrollView:
        GridLayout:
            id: box_share2
            cols: 1
            size_hint_y: None
            size_hint_x: 0.5
            spacing: 5
            padding: 130
            height: self.minimum_height
            canvas:
                Color: 
                    rgb: 0, 0, 0
                Rectangle:
                    pos: self.pos
                    size: self.size         

<ContinueEditingScreen>:
    name: "continueediting"
    GarageNameBoxLayout:
    BackHomeWidget:
        SmallNavButton:
            on_release: app.root.current = "edit"
            text: "Back"
            pos: root.x, root.top - (2.25*(self.height))
4

1 回答 1

1

您的代码可以在以下方面进行改进:

  • 您不必在 .py 中创建 box_share2 ,因为您是在 .kv 中创建它

  • 当您使用时,sm = ScreenManager()您正在创建另一个ScreenManager与原始版本不同的东西,这是没有必要的。

  • 没有必要使用rangeandlen来降低代码的可读性,你只需要迭代。

  • 如果我们查看 .kv 的结构,我们会看到演示对象是 ,ScreenManager因此您可以通过 .kv 获取它app.root

使用上面的代码,解决方案是:

[...]

class GarageNameBoxLayout(BoxLayout):
    def __init__(self, **kwargs):
        super(GarageNameBoxLayout, self).__init__(**kwargs)
        self.orientation = "vertical"
        Clock.schedule_interval(self.create_button, 5)

    def create_button(self, *args):
        self.box_share2.clear_widgets()
        app = App.get_running_app()
        sm = app.root

        #put GarageNameStartList data into app class, then pull from it in this class
        top_button_share = 1.1
        color = (.4, .4, .4, 1)
        for text in app.GarageNameStartList:
            top_button_share -= .4
            id_ = text
            button_share = Button(background_normal='',
                                  background_color = color,
                                  id = id_,
                                  pos_hint = {"x": 0, "top": top_button_share},
                                  size_hint_y = None,
                                  height = 60,
                                  font_size = 30,
                                  text = text)
            button_share.bind(on_press=lambda *args: setattr(sm, 'current', "main"))
            self.box_share2.add_widget(button_share)

[...]
于 2018-03-13T21:26:59.893 回答