“确认”用户点击

时间:2019-09-12 14:45:00

标签: python python-3.x user-interface tkinter

我看到,当您按下电视遥控器上的按钮时,它不会立即进入该频道,过一段时间后它将降落在该频道上,但是如果您在特定时间段内按下该按钮,它将不会降落到该频道上。

是否可以在tkInter中执行此操作,如果用户在一定时间段内(在本例中为2秒钟)单击按钮,则除非用户不单击按钮,否则该函数将不会执行。

为澄清起见,我想将命令执行延迟2秒,以便在用户再次按下相同按钮时可以再次取消命令。

2 个答案:

答案 0 :(得分:2)

您始终可以断开按钮和操作的连接,并在它们之间放置一个可以取消的计时器。 Tkinter提供Widget.after() method来延迟调用回调。您也可以为此使用线程来给予更多控制。

以下实现可以用作任何tkInter元素的回调;它需要一个延迟(以秒为单位的浮点数),并且一旦延迟过去而没有其他点击,就会进行回调。调用DelayedCancellable()以及取消取消时,会立即调用另外两个可选的回调:

import time
from threading import Thread, Event

class DelayedCancellable:
    def __init__(self, delay, after_delay, invoked=None, cancelled=None):
        super().__init__()
        self._after_delay = after_delay
        self._on_invoked = invoked
        self._on_cancelled = cancelled
        self._delay = delay
        self._thread = None
        self._cancelled = Event()

    def __call__(self):
        if self._thread is not None and self._thread.is_alive():
            self._cancelled.set()
        else:
            if self._on_invoked is not None:
                self._on_invoked()
            self._thread = Thread(target=self._delayed_execution)
            self._thread.start()

    def _delayed_execution(self):
        try:
            if self._cancelled.wait(self._delay):
                # we got cancelled, exit
                if self._on_cancelled is not None:
                    self._on_cancelled()
                return
            self._after_delay()
        finally:
            self._thread = None
            self._cancelled.clear()

使用它时,以秒为单位传递延迟作为浮点数,并回调:

from tkinter import Button

def callback():
    print("Hello, world!")

b = Button(
    master,
    text="Click me!",
    command=DelayedCancellable(2.0, callback)
)

上面的按钮将导致打印Hello, world!,除非您在2秒钟内再次单击该按钮。

可以使用额外的invokedcancelled操作来更新UI,以便为用户提供更多反馈:

from tkinter import Button, RAISED, SUNKEN

def button_invoked():
    b.config(relief=SUNKEN)

def button_cancelled():
    b.config(relief=RAISED)

def callback():
    button_cancelled()  # clear state
    print("Hello, world!")

b = Button(
    master,
    text="Click me!",
    command=DelayedCancellable(2.0, callback, button_invoked, button_cancelled)
)

答案 1 :(得分:2)

与Martijn Pieters不同的方法。我已经使用.after安排了一个事件在2秒后发生,而不是一个单独的线程。

单击一次按钮将在2秒钟后调用ConfirmedAction函数。在2秒的窗口中再次单击该按钮,将取消计时器。

import tkinter as tk

def ConfirmedAction():
    print("Doing something")

class ConfirmButton(tk.Button):
    def __init__(self,master,**kw):
        self.confirmcommand = kw.pop('confirm',None)
        super(ConfirmButton, self).__init__(master, **kw)
        self.timer = None
        self['command'] = self._clicked
    def _clicked(self):
        if not self.timer:
            self.timer = self.after(2000,self._doAction)
        else:
            self.after_cancel(self.timer)
            self.timer = None
            print("Action Cancelled")
    def _doAction(self):
        self.confirmcommand()
        self.timer = None

root = tk.Tk()
btn1 = ConfirmButton(root,text="Hello",confirm=ConfirmedAction)
btn1.grid()
root.mainloop()