对于动态创建的按钮,使用On_Press事件更改屏幕而不使用KV语言

时间:2018-03-13 21:07:46

标签: python button kivy onpress

问题:

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

目标:

能够通过点击动态创建的按钮

导航到新屏幕

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

我已经尝试过的事情:

  1. 使用button_share.bind(on_press = self.changer),然后执行此操作:
  2. def changer(self,*args):
        ScreenManager()
        screenmanager.current = 'MainScreen'
    

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

    怀疑:

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

    1. 使用:
    2. button_share.bind(on_press=partial(app.sm.setter('current'), (app.sm, "MainScreen")))`
      

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

      以下是完全可运行的示例:

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

      Python代码:

      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()
      

      KV代码:

      #: 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))
      

1 个答案:

答案 0 :(得分:1)

您的代码可以通过以下方式进行改进:

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

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

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

  • 如果我们查看.kv的结构,我们会看到表示对象是ScreenManager,因此您可以通过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)

[...]