我看到,当您按下电视遥控器上的按钮时,它不会立即进入该频道,过一段时间后它将降落在该频道上,但是如果您在特定时间段内按下该按钮,它将不会降落到该频道上。
是否可以在tkInter中执行此操作,如果用户在一定时间段内(在本例中为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秒钟内再次单击该按钮。
可以使用额外的invoked
和cancelled
操作来更新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()