单击时中断 Kivy 切换按钮状态更改

时间:2021-07-27 12:33:03

标签: python kivy kivy-language

我有一个用于启动和停止进程的切换按钮。当进程停止时,我会出现一个弹出框,要求用户输入密码以确认他们要结束进程。

只有在提供了正确的密码后,我才希望切换按钮的状态从“向下”更改为“正常”,因为正在结束的进程使用切换按钮状态来确定进程是否应该继续运行。

>

我目前遇到的问题是,在按下切换按钮的那一刻,状态从“向下”变为“正常”,从而在显示用于验证用户的密码框之前结束该过程。< /p>

有关如何在单击切换按钮时中断其状态更改的任何建议?

已编辑!

main.py:

# import kivy modules
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.properties import ObjectProperty
from kivy.config import Config
Config.set('kivy', 'exit_on_escape', '0')

# import self defined backend class
from ProcessPanel import ProcessPanel


class Automation(App):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def build(self):
        return AppPanels()


class AppPanels(TabbedPanel):

    process_tab = ObjectProperty(None)
    process_tab_panel = ObjectProperty(None)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)


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

ProcessPanel.py:

# import kivy modules
from kivy.properties import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.properties import ObjectProperty

# import self defined backend classes
from ToolStopWindow import ToolStopWindow


class ProcessPanel(BoxLayout):

    process_toggle = ObjectProperty()

    def __init__(self, **kwargs):

        # inherit BoxLayout Attributes and Methods
        super().__init__(**kwargs)
        self.num = 0
        # create the custom query pop up window
        self.TSW = ToolStopWindow(passwd="testPassword",
                                  title_text="Are you sure you want to stop the process?",
                                  sub_title_text="Enter Password to Stop Process...",
                                  external_button=self.process_toggle)

        self.TSW.confirm_btn.bind(on_release=self.end_process)

        self.process_toggle.bind(_do_press=self.toggle_switch_state())

        self.process_schedule = []

    # Determine if process has been activated
    def toggle_switch_state(self):
        if self.process_toggle.state == "normal":
            self.process_schedule = Clock.schedule_interval(self.my_process, 5)
            self.process_toggle._do_unpress()
        else:
            self.TSW.open()

    def my_process(self, dt):
        self.num = self.num + 1
        print(self.num)

    def end_process(self):
        self.process_schedule.cancel()


class StartStopToggle(ToggleButton):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def _do_unpress(self):
        if (not self.allow_no_selection and
                self.group and self.state == 'down'):
            return
        self._release_group(self)
        self.state = 'normal' if self.state == 'down' else 'down'

ToolStopWindow.py:

import time

from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup


class ToolStopWindow(Popup):

    passwd_box = ObjectProperty()
    passwd = ObjectProperty()

    confirm_btn = ObjectProperty()
    confirm_btn_callback = ObjectProperty()

    cancel_btn = ObjectProperty()

    title_text = ObjectProperty()

    sub_title = ObjectProperty()
    sub_title_text = ObjectProperty()

    external_button = ObjectProperty()

    def __init__(self, **kwargs):

        super().__init__(**kwargs)
        self.is_true = False

    def check_pass(self):

        if self.passwd_box.text == self.passwd:
            self.sub_title.text = "Password Correct!"
            time.sleep(1)
            self.external_button._do_unpress()
            self.dismiss()

        else:
            self.is_true = False
            self.passwd_box.text = ""
            self.sub_title.text = "Invalid Password!"

        return

    def reset_label_text(self):

        if self.sub_title.text != self.sub_title_text:
            self.sub_title.text = self.sub_title_text

自动化.kv:

<AppPanels>:
    process_tab: process_tab
    process_tab_panel: process_tab_panel

    id: Tab_Level
    size_hint: 1, 1
    pos_hint: {'center_x': .5, 'center_y': .5}
    do_default_tab: False
    tab_pos: 'top_mid'
    tab_width: root.width/5
    font_size: 24

    TabbedPanelItem:
        id: process_tab
        text: "Process Tab"

        ProcessPanel:
            id: process_tab_panel

<ProcessPanel>:
    orientation: "vertical"

    process_toggle: process_toggle

    Button:
        text: "normal button"
        on_release: root.my_process(self)

    StartStopToggle:
        id: process_toggle
        on_state: root.toggle_switch_state()

<StartStopToggle>:
    text: "Start Process Schedule"
    font_size: 36

<ToolStopWindow>:
    id: close_window
    auto_dismiss: False
    title: root.title_text
    size_hint: 0.8, 0.8

    passwd_box: passwd_box
    confirm_btn: confirm_btn
    cancel_btn: cancel_btn
    sub_title: sub_title

    BoxLayout:
        id: main_panel
        orientation: "vertical"

        Label:
            id: sub_title
            text: root.sub_title_text
            font_size: 36

        TextInput:
            id: passwd_box
            multiline: False
            password: True
            on_text: root.reset_label_text()
            on_text_validate: root.check_pass()

        BoxLayout:
            id: Buttons
            orientation: "horizontal"

            Button:
                id: confirm_btn
                text: "Confirm!"
                on_release: root.check_pass()

            Button:
                id: cancel_btn
                text: "Cancel"
                on_release: root.dismiss()

我想做的是将 _do_press 函数绑定到 ProcessPanel 类中的一个函数,但我一直收到一个属性错误,说“'None type' 对象没有属性 'bind'”,我认为这是因为我分配给 UI 对象的 id 是在 init 之后分配的?

此外,我在如何取消我创建的时钟方面遇到了一些困难,以便在提供正确密码时定期调用 my_process 函数。

我希望这个例子的添加有帮助!

2 个答案:

答案 0 :(得分:2)

我可能会将 ToggleButton 子类化以覆盖 _do_press 方法来完成打开弹出窗口的工作,然后

https://github.com/kivy/kivy/blob/master/kivy/uix/behaviors/togglebutton.py#L112-L115

class ConfirmPopup(Popup):
    button = ObjectProperty()
    password = StringProperty()

    def check_password(self, pass):
        if self.ids.password.text == self.password:
             self.button._do_unpress()
        self.dismiss()

class PasswordCheckedToggleButton(ToggleButton):
    def _do_press(self):
        ConfirmPopup(button=self, password="secret").open()
   
    def _do_unpress(self):
        if (not self.allow_no_selection and
                self.group and self.state == 'down'):
            return
        self._release_group(self)
        self.state = 'normal' if self.state == 'down' else 'down'

类似的东西

<ConfirmPopup>:
    title: "password!"
    BoxLayout:
        orientation: "vertical"
        TextInput:
           id: password
        Button:
           text: "it’ a me!"
           on_release: root.check_password()

答案 1 :(得分:0)

嗨,我想出了如何在我的代码中使用您的答案,并在下面发布了答案,以防有人觉得它有用。

不知道为什么,但在一个独立的例子中, on_request_close 功能不起作用,尽管代码与我正在处理的项目相同并且它在那里工作,花了一段时间试图定位问题但无法找到它......无论哪种方式它现在都对我有用,所以即使我尝试关闭应用程序,我也会被要求输入密码以在应用程序关闭之前停止该过程

main.py:

# import kivy modules
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.properties import ObjectProperty
from kivy.config import Config
Config.set('kivy', 'exit_on_escape', '0')

# import self defined backend class
from StartStopToggle import StartStopToggle
from ProcessPanel import ProcessPanel
from ToolStopWindow import ToolStopWindow


class Automation(App):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def build(self):
        Window.bind(on_request_close=self.on_request_close)
        return AppPanels()

    def on_request_close(self, *args):
        if self.root.process_tab_panel.process_toggle.state == "down":
            self.root.process_tab_panel.process_toggle.TSW.opening_object = self
            self.root.process_tab_panel.process_toggle.TSW.open()
        else:
            self.stop()
        return True

    def do_tsw_function(self):
        self.stop()


class AppPanels(TabbedPanel):

    process_tab = ObjectProperty(None)
    process_tab_panel = ObjectProperty(None)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)




if __name__ == '__main__':
    Automation().run()# import kivy modules
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.properties import ObjectProperty
from kivy.config import Config
Config.set('kivy', 'exit_on_escape', '0')

# import self defined backend class
from ProcessPanel import ProcessPanel


class Automation(App):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def build(self):
        return AppPanels()


class AppPanels(TabbedPanel):

    process_tab = ObjectProperty(None)
    process_tab_panel = ObjectProperty(None)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)


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

ProcessPanel.py:

# import kivy modules
from kivy.properties import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.properties import ObjectProperty

# import self defined backend classes
from ToolStopWindow import ToolStopWindow


class ProcessPanel(BoxLayout):

    process_toggle = ObjectProperty()

    def __init__(self, **kwargs):

        # inherit BoxLayout Attributes and Methods
        super().__init__(**kwargs)
        self.num = 0
        # create the custom query pop up window

        self.process_schedule = []

    # Determine if process has been activated
    def toggle_switch_state(self):
        if self.process_toggle.state == "down":
            self.process_schedule = Clock.schedule_interval(self.my_process, 5)
            self.process_toggle.text = "Stop Process Schedule"
        else:
            self.process_schedule.cancel()
            self.process_toggle.text = "Start Process Schedule"

    def my_process(self, dt):
        self.num = self.num + 1
        print(self.num)

    def end_process(self):
        self.process_schedule.cancel()

ToolStopWindow.py

import time

from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup


class ToolStopWindow(Popup):

    passwd_box = ObjectProperty()
    passwd = ObjectProperty()

    confirm_btn = ObjectProperty()
    confirm_btn_callback = ObjectProperty()

    cancel_btn = ObjectProperty()

    title_text = ObjectProperty()

    sub_title = ObjectProperty()
    sub_title_text = ObjectProperty()

    opening_object = ObjectProperty()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def check_pass(self):
        if self.passwd_box.text == self.passwd:
            self.passwd_box.text = ""
            self.sub_title.text = "Password Correct!"
            time.sleep(1)
            self.dismiss()
            self.opening_object.do_tsw_function()

        else:
            self.passwd_box.text = ""
            self.sub_title.text = "Invalid Password!"

    def reset_label_text(self):
        if self.sub_title.text != self.sub_title_text:
            self.sub_title.text = self.sub_title_text

StartStopToggle.py:

from kivy.uix.togglebutton import ToggleButton
from ToolStopWindow import ToolStopWindow


class StartStopToggle(ToggleButton):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.TSW = ToolStopWindow(passwd="password",
                                  title_text="Are you sure you want to stop the process?",
                                  sub_title_text="Enter Password to Stop Process...")

    def _do_press(self):
        self.TSW.opening_object = self
        self.TSW.open()

    def do_tsw_function(self):
        self._do_actual_press()

    def _do_actual_press(self):
        if (not self.allow_no_selection and
                self.group and self.state == 'down'):
            return
        self._release_group(self)
        self.state = 'normal' if self.state == 'down' else 'down'

自动化.kv

<AppPanels>:
    process_tab: process_tab
    process_tab_panel: process_tab_panel

    id: Tab_Level
    size_hint: 1, 1
    pos_hint: {'center_x': .5, 'center_y': .5}
    do_default_tab: False
    tab_pos: 'top_mid'
    tab_width: root.width/5
    font_size: 24

    TabbedPanelItem:
        id: process_tab
        text: "Process Tab"

        ProcessPanel:
            id: process_tab_panel

<ProcessPanel>:
    orientation: "vertical"

    process_toggle: process_toggle

    Button:
        text: "normal button"
        on_release: root.my_process(self)

    StartStopToggle:
        id: process_toggle
        on_state: root.toggle_switch_state()

<StartStopToggle>:
    text: "Start Query Schedule"


<ToolStopWindow>:
    id: close_window
    auto_dismiss: False
    title: root.title_text
    size_hint: 0.8, 0.8

    passwd_box: passwd_box
    confirm_btn: confirm_btn
    cancel_btn: cancel_btn
    sub_title: sub_title

    BoxLayout:
        id: main_panel
        orientation: "vertical"

        Label:
            id: sub_title
            text: root.sub_title_text
            font_size: 36

        TextInput:
            id: passwd_box
            multiline: False
            password: True
            on_text: root.reset_label_text()
            on_text_validate: root.check_pass()

        BoxLayout:
            id: Buttons
            orientation: "horizontal"

            Button:
                id: confirm_btn
                text: "Confirm!"
                on_release: root.check_pass()

            Button:
                id: cancel_btn
                text: "Cancel"
                on_release: root.dismiss()
相关问题