【问题标题】:Kivy: dismiss() doesn't work on my ModalView widgetKivy:dismiss() 在我的 ModalView 小部件上不起作用
【发布时间】:2017-04-13 07:19:48
【问题描述】:

我正在制作一个ModalView 小部件并尝试通过按下它上面的按钮来关闭它。按钮按下的回调转到假设关闭它的方法。

这是 main.kv:

<MainFrame>:
    id: main_frame
    ScreenMaster:
        id: screen_master
        StartScreen:
            id: start_screen
            SettingsPopup:
                id: settings_popup
        GameScreen:
            id: game_screen
            GameOverPopup:
                id: gameover_popup

还有gameoverpopup.kv:

<GameOverPopup>:
    auto_dismiss: False
    pos_hint: {'center_x': .5, 'center_y': .5}
    size_hint: .7, .4
    RelativeLayout:
        Button:
            id: close_button
            pos_hint: {'x': .1, 'y': .05}
            size_hint: .8, .2
            text: 'PLAY AGAIN'
            on_press: root.done()
        Label:
            pos_hint: {'x': .2, 'y': .8}
            size_hint: .6, .15
            font_size: 32
            text: 'YOU WON'

还有main.py:

# kivy includes
Builder.load_file('startscreen.kv')
Builder.load_file('gamescreen.kv')
Builder.load_file('settingspopup.kv')
Builder.load_file('gameoverpopup.kv')

class StartScreen(Screen):
    pass

class GameScreen(Screen):
    pass

class ScreenMaster(ScreenManager):
    pass

class SettingsPopup(ModalView):
    pass

class GameOverPopup(ModalView):
    def done(self):
        self.dismiss()

class MainFrame(AnchorLayout):
    pass

class MainApp(App):
    def on_pause(self):
        return True

    def build(self):
        return MainFrame()

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

按下Play again 按钮会调用done() 方法,但ModalView 小部件不会关闭。我该如何解决这个问题并让它消失?

【问题讨论】:

    标签: python kivy kivy-language


    【解决方案1】:

    自己找到了解决方案:

    <MainFrame>:
        id: main_frame
        ScreenMaster:
            id: screen_master
            StartScreen:
                id: start_screen
                SettingsPopup:
                    id: settings_popup
                    on_parent: if self.parent == start_screen: start_screen.remove_widget(self)
            GameScreen:
                id: game_screen
                GameOverPopup:
                    id: gameover_popup
                    on_parent: if self.parent == game_screen: game_screen.remove_widget(self)
    

    所以我们实例化这些弹出窗口并立即关闭它们。现在我们可以随时打开它们。

    【讨论】:

      【解决方案2】:

      ModalView 或从它继承的任何东西 (Popup) 并不意味着作为子元素添加到任何地方。默认情况下,ModalView 直接附加到 Window,正如您在调用 open() 方法时在 docs 中提到的那样。

      当您将其作为子项添加到某处时,您会自动使其可见,这是不好,因为您误用了该小部件的用途。

      您应该将其作为类/规则在某处设置,并在需要显示时调用 open() 方法。当您需要手动关闭它时,您需要将一些方法附加到on_open 以将ModalView 类的实例存储在某处并通过该实例调用dismiss() 或在ModalView 上的某处放置一个按钮。

      通过您的回答,您只会修补您误用小部件的错误。 :)

      有两种方法可以打开ModalView(或Popup):

      蟒蛇:

      SettingsPopup().open()
      

      kv:

      #:import Factory kivy.factory.Factory
      Factory.SettingsPopup().open()
      

      【讨论】:

      • 是的,你是对的。它会导致“弱引用对象不再存在”错误。但问题是 - 我需要这个参考。我想说的是:在那些 SettingsPopup 和 GameOverPopup 上我有一个按钮,它们有一个回调到它们各自的类,但是没有这个引用我不能通过 id 访问 GameScreen 或 StartScreen 的任何方法。例如,在 GameOverPopup 上,我有一个“再次播放”按钮,它调用 gamescreen.game_restart(),如果我没有此参考,我无法调用它...
      • @Roman 然后将其存储在某处,而不是将其作为子项添加到某处:)
      • @Roman 您可以使用Popup__init__() 方法来执行例如这个:App.get_running_app().my_popup = self 然后在 kv 中执行 app.my_popup。此外,在on_dismiss 事件中执行App.get_running_app().my_popup = None 可能是个好主意。 :)
      • 其实我找到了另一种方法 :) 从这里:kivy.org/docs/guide/lang.html 引用小部件部分,在引用 ID 中使用 self
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-21
      • 1970-01-01
      • 2021-01-16
      • 2013-01-07
      • 2014-11-02
      相关资源
      最近更新 更多