首页 > 解决方案 > 单击时中断 Kivy 切换按钮状态更改

问题描述

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

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

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

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

已编辑!

主要.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()

进程面板.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' object has no attribute'bind'”,我认为这是因为 id 是 i' m 分配给 UI 对象是在init之后分配的吗?

此外,当给出正确的密码时,我对如何取消我创建的时钟来定期调用 my_process 函数有点困惑。

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

标签: pythonkivykivy-language

解决方案


我可能会将 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: &quot;vertical"
        TextInput:
           id: password
        Button:
           text: &quot;it’ a me!"
           on_release: root.check_password()

推荐阅读