Python kivymd 退出时弹出

Posted

技术标签:

【中文标题】Python kivymd 退出时弹出【英文标题】:Python kivymd Popup when exiting 【发布时间】:2019-01-13 22:15:06 【问题描述】:

我正在尝试创建一个用于退出应用程序的弹出窗口。但我不断收到错误“object.init() 没有参数”。在我的项目文件夹中,我有一个名为“应用程序”的文件夹。在此文件夹中,我已将相关的 kivymd *.py 文件复制到名为 kivymd 的文件夹中。我很感激任何帮助。单击退出应用程序选项后,我想要一个带有按钮的弹出窗口来接受或取消应用程序的退出。

在应用程序文件夹中,我有三个文件:main.py、main.kv 和 labels.py(用于将标签注入 main.py 和 main.kv)。

main.py 包含应用程序的所有逻辑。

# -*- coding: utf-8 -*-

import os

# Set virtual keyboard
from kivy.app import App
from kivy.config import Config
Config.set('kivy', 'keyboard_mode', 'systemandmulti')
from kivy.uix.popup import Popup
from kivy.uix.button import Button


from kivy.core.window import Window
Window.fullscreen = "auto"
from kivy.lang import Builder
from functools import partial


from kivymd.list import BaseListItem
from kivymd.material_resources import DEVICE_TYPE
from kivymd.navigationdrawer import MDNavigationDrawer, NavigationDrawerHeaderBase
from kivymd.theming import ThemeManager
from kivymd.button import MDIconButton


class HackedDemoNavDrawer(MDNavigationDrawer):
    # DO NOT USE
    def add_widget(self, widget, index=0):
        if issubclass(widget.__class__, BaseListItem):
            self._list.add_widget(widget, index)
            if len(self._list.children) == 1:
                widget._active = True
                self.active_item = widget
            # widget.bind(on_release=lambda x: self.panel.toggle_state())
            widget.bind(on_release=lambda x: x._set_active(True, list=self))
        elif issubclass(widget.__class__, NavigationDrawerHeaderBase):
            self._header_container.add_widget(widget)
        else:
            super(MDNavigationDrawer, self).add_widget(widget, index)


class MainApp(App):
    theme_cls = ThemeManager()
    title = "Application"

    def build(self):
        main_widget = Builder.load_file(
            os.path.join(os.path.dirname(__file__), "./main.kv")
        )
        self.theme_cls.theme_style = 'Dark'

        main_widget.ids.text_field_error.bind(
            on_text_validate=self.set_error_message,
            on_focus=self.set_error_message)
        self.bottom_navigation_remove_mobile(main_widget)
        return main_widget

    def stop(self, *largs):
        # Open the popup you want to open and declare callback if user pressed `Yes`
        popup = ExitPopup(title="Are you sure?",
                          content=Button(text='Close me!'),
                          size=(400, 400), size_hint=(None, None)
                          )
        popup.bind(on_confirm=partial(self.close_app, *largs))
        popup.open()

    def close_app(self, *largs):
        super(MainApp, self).stop(*largs)

    def bottom_navigation_remove_mobile(self, widget):
        # Removes some items from bottom-navigation demo when on mobile
        if DEVICE_TYPE == 'mobile':
            widget.ids.bottom_navigation_demo.remove_widget(widget.ids.bottom_navigation_desktop_2)
        if DEVICE_TYPE == 'mobile' or DEVICE_TYPE == 'tablet':
            widget.ids.bottom_navigation_demo.remove_widget(widget.ids.bottom_navigation_desktop_1)

    def set_error_message(self, *args):
        if len(self.root.ids.text_field_error.text) == 2:
            self.root.ids.text_field_error.error = True
        else:
            self.root.ids.text_field_error.error = False

    def on_pause(self):
        return True

    def on_stop(self):
        pass


class ExitPopup(Popup):

    def __init__(self, **kwargs):
        super(ExitPopup, self).__init__(**kwargs)
        self.register_event_type('on_confirm')

    def on_confirm(self):
        pass

    def on_button_yes(self):
        self.dispatch('on_confirm')


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

main.kv是使用kv语言来判断用户界面

# main.kv
#:kivy 1.10.1
#:import Toolbar kivymd.toolbar.Toolbar
#:import MDNavigationDrawer application.kivymd.navigationdrawer.MDNavigationDrawer
#:import NavigationLayout application.kivymd.navigationdrawer.NavigationLayout
#:import NavigationDrawerDivider application.kivymd.navigationdrawer.NavigationDrawerDivider
#:import NavigationDrawerToolbar application.kivymd.navigationdrawer.NavigationDrawerToolbar
#:import NavigationDrawerSubheader application.kivymd.navigationdrawer.NavigationDrawerSubheader
#:import MDTextField application.kivymd.textfields.MDTextField
#:import labels application.labels

NavigationLayout:
    id: nav_layout
    MDNavigationDrawer:
        id: nav_drawer
        NavigationDrawerToolbar:
            title: labels.NAVIGATION
        NavigationDrawerIconButton:
            icon: 'checkbox-blank-circle'
            text: labels.SYSTEM_PARAMETERS
            on_release: app.root.ids.scr_mngr.current = 'system_parameters'
        NavigationDrawerIconButton:
            icon: "checkbox-blank-circle"
            text: labels.CLOSE_APPLICATION
            on_release: app.stop()
    BoxLayout:
        orientation: 'vertical'
        halign: "center"
        Toolbar:
            id: toolbar
            title: labels.APPLICATION_NAME
            md_bg_color: app.theme_cls.primary_color
            background_palette: 'Primary'
            background_hue: '500'
            left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]]
            #right_action_items: [['dots-vertical', lambda x: app.root.toggle_nav_drawer()]]
        ScreenManager:
            id: scr_mngr
            Screen:
                name: 'system_parameters'
                BoxLayout:
                    orientation: "horizontal"
                    BoxLayout:
                        orientation: 'vertical'
                        size_hint_y: None
                        height: self.minimum_height
                        padding: dp(48)
                        spacing: 10
                        MDTextField:
                            hint_text: "Helper text on focus"
                            helper_text: "This will disappear when you click off"
                            helper_text_mode: "on_focus"
                            input_filter: "int"
                    BoxLayout:
                        orientation: 'vertical'
                        size_hint_y: None
                        height: self.minimum_height
                        padding: dp(48)
                        spacing: 10
                        MDTextField:
                            hint_text: "Helper text on focus"
                            helper_text: "This will disappear when you click off"
                            helper_text_mode: "on_focus"
                            input_filter: "float"

            Screen:
                name: 'textfields'
                ScrollView:
                    BoxLayout:
                        orientation: 'vertical'
                        MDTextField:
                            id: text_field_error
                            hint_text: "Helper text on error (Hit Enter with two characters here)"
                            helper_text: "Two is my least favorite number"
                            helper_text_mode: "on_error"

            Screen:
                name: 'nav_drawer'
                HackedDemoNavDrawer:
                    # NavigationDrawerToolbar:
                    #     title: "Navigation Drawer Widgets"
                    NavigationDrawerIconButton:
                        icon: 'checkbox-blank-circle'
                        text: "Badge text ---->"
                        badge_text: "99+"
                    NavigationDrawerIconButton:
                        active_color_type: 'accent'
                        text: "Accent active color"
                    NavigationDrawerIconButton:
                        active_color_type: 'custom'
                        text: "Custom active color"
                        active_color: [1, 0, 1, 1]
                    NavigationDrawerIconButton:
                        use_active: False
                        text: "Use active = False"
                    NavigationDrawerIconButton:
                        text: "Different icon"
                        icon: 'alarm'
                    NavigationDrawerDivider:
                    NavigationDrawerSubheader:
                        text: "NavigationDrawerSubheader"
                    NavigationDrawerIconButton:
                        text: "NavigationDrawerDivider \/"
                    NavigationDrawerDivider:

labels.py 很短

# labels.py
APPLICATION_NAME = "Application"
CLOSE_APPLICATION = "Close Application"
NAVIGATION = "Navigation"
SYSTEM_PARAMETERS = "System Parameters"

【问题讨论】:

【参考方案1】:

解决方案 - 使用 KivyMD MDDialog

在以下示例中,它使用 KivyMD MDDialog 作为弹出窗口。

片段

from kivymd.dialog import MDDialog
from kivymd.label import MDLabel
from kivy.metrics import dp


class ExitPopup(MDDialog):

    def __init__(self, **kwargs):
        super(ExitPopup, self).__init__(**kwargs)
        content = MDLabel(font_style='Body1',
                          theme_text_color='Secondary',
                          text="Are you sure?",
                          size_hint_y=None,
                          valign='top')
        content.bind(texture_size=content.setter('size'))
        self.dialog = MDDialog(title="Close Application",
                               content=content,
                               size_hint=(.3, None),
                               height=dp(200))

        self.dialog.add_action_button("Close me!",
                                      action=lambda *x: self.dismiss_callback())
        self.dialog.open()

    def dismiss_callback(self):
        self.dialog.dismiss()
        App.get_running_app().close_app()

...

    def stop(self, *largs):
        # Open the popup you want to open and declare callback if user pressed `Yes`
        ExitPopup()

输出 - KivyMD MDDialog

解决方案 - 使用 Kivy 弹出窗口

详情请参考step-by-step、sn-p和example。

    添加导入语句,from kivy.uix.button import ButtonMDIconButton 替换为Button

片段

def stop(self, *largs):
    # Open the popup you want to open and declare callback if user pressed `Yes`
    popup = ExitPopup(title="Are you sure?",
                      content=Button(text='Close me!'),
                      size=(400, 400), size_hint=(None, None)
                      )

示例 - Kivy 弹出窗口

main.py

​​>
# -*- coding: utf-8 -*-

import os

# Set virtual keyboard
from kivy.app import App
from kivy.config import Config
from kivy.uix.popup import Popup
from kivy.uix.button import Button

Config.set('kivy', 'keyboard_mode', 'systemandmulti')
from kivy.core.window import Window
# Window.fullscreen = "auto"
from kivy.lang import Builder
from functools import partial


from kivymd.list import BaseListItem
from kivymd.material_resources import DEVICE_TYPE
from kivymd.navigationdrawer import MDNavigationDrawer, NavigationDrawerHeaderBase
from kivymd.theming import ThemeManager


class HackedDemoNavDrawer(MDNavigationDrawer):
    # DO NOT USE
    def add_widget(self, widget, index=0):
        if issubclass(widget.__class__, BaseListItem):
            self._list.add_widget(widget, index)
            if len(self._list.children) == 1:
                widget._active = True
                self.active_item = widget
            # widget.bind(on_release=lambda x: self.panel.toggle_state())
            widget.bind(on_release=lambda x: x._set_active(True, list=self))
        elif issubclass(widget.__class__, NavigationDrawerHeaderBase):
            self._header_container.add_widget(widget)
        else:
            super(MDNavigationDrawer, self).add_widget(widget, index)


class MainApp(App):
    theme_cls = ThemeManager()
    title = "Application"

    def build(self):
        main_widget = Builder.load_file(
            os.path.join(os.path.dirname(__file__), "./main.kv")
        )
        self.theme_cls.theme_style = 'Dark'

        main_widget.ids.text_field_error.bind(
            on_text_validate=self.set_error_message,
            on_focus=self.set_error_message)
        self.bottom_navigation_remove_mobile(main_widget)
        return main_widget

    def stop(self, *largs):
        # Open the popup you want to open and declare callback if user pressed `Yes`
        popup = ExitPopup(title="Are you sure?",
                          content=Button(text='Close me!'),
                          size=(400, 400), size_hint=(None, None)
                          )
        popup.bind(on_confirm=partial(self.close_app, *largs))
        popup.open()

    def close_app(self, *largs):
        super(MainApp, self).stop(*largs)

    def bottom_navigation_remove_mobile(self, widget):
        # Removes some items from bottom-navigation demo when on mobile
        if DEVICE_TYPE == 'mobile':
            widget.ids.bottom_navigation_demo.remove_widget(widget.ids.bottom_navigation_desktop_2)
        if DEVICE_TYPE == 'mobile' or DEVICE_TYPE == 'tablet':
            widget.ids.bottom_navigation_demo.remove_widget(widget.ids.bottom_navigation_desktop_1)

    def set_error_message(self, *args):
        if len(self.root.ids.text_field_error.text) == 2:
            self.root.ids.text_field_error.error = True
        else:
            self.root.ids.text_field_error.error = False

    def on_pause(self):
        return True

    def on_stop(self):
        pass


class ExitPopup(Popup):

    def __init__(self, **kwargs):
        super(ExitPopup, self).__init__(**kwargs)
        self.register_event_type('on_confirm')

    def on_confirm(self):
        pass

    def on_button_yes(self):
        self.dispatch('on_confirm')


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

输出 - Kivy 弹出窗口

【讨论】:

我编辑了我的 main.py,但它仍然不起作用。你能发布你的 main.py 吗? 我更新了我的帖子。有一点我不得不复制 Config.set("kivy", "keyboard_mode", "systemandmulti") 旁边的 from kivy.config import Config 以确保虚拟键盘在拖动时不会自行关闭。弹出窗口与标准按钮一起使用,但单击该按钮不会关闭应用程序。 我想我需要更改 kv 文件以触发相应的功能。 请参阅用 KivyMD MDDialog 小部件替换 Kivy Popup 小部件的更新帖子。 新版本就像一个魅力!非常感谢您的努力和时间!

以上是关于Python kivymd 退出时弹出的主要内容,如果未能解决你的问题,请参考以下文章

[UWP]在应用退出时弹出确认提示框

如何用python做一个在windows关机时弹出一句消息提示的小程序?

pycharm导入工程文件执行程序时弹出Edit configuration

如何在 KivyMD、Python 中制作下拉菜单

尝试使用 KivyMD 和 Python 显示 PDF 文件

如何修复 Kivymd MDDataTable python3 的“内联错误”