I have made a GUI using TkInter.
Now I am trying to perform an action after a key press.
However, I don't want the action to perform twice when I click the button twice.
But rather, the program should wait until the previous action is finished before it starts waiting for the next key press.
I cannot seem to achieve this, even thought the command handler returns "break"
.
See below a minimal working example, where if you press the <Left>
button multiple times, the code also executes multiple times. How should I change the code to achieve the desired performance?
import tkinter as tk
import time
class App(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self)
# Create handler
def event_handler(event):
print('One run for event', event)
time.sleep(1)
print('Done')
return "break"
# Button
self.button = tk.Button(
master=self,
text='Test',
command = event_handler
)
self.button.grid()
self.bind('<Left>', event_handler)
self.focus()
if __name__ == "__main__":
root = tk.Tk()
root.title("TestTool")
# Start application
app = App(root)
app.pack(fill="both", expand=True)
root.mainloop()
CodePudding user response:
When You execute Your event_handler
with time.sleep(1)
, You are effectively blocking any other event execution. But event triggers are accumulating and executed one after another how each event_handler
starts and ends. It creates effect of serial execution of event_handler
.
What You want is to set some flag which will indicates Your event state. Then You have to process all accumulated events before Your return
from event_handler
. This will cause all events to execute, but immediately return
, because flag is set to True
: event is running.
Here is code snippet:
import time
import tkinter as tk
class App(tk.Frame):
event_running = False
def __init__(self, parent):
tk.Frame.__init__(self)
# Create handler
def event_handler(event=None):
# Check if event is running
if self.event_running:
return False
# Lock event until it's finished
self.event_running = True
print('One run for event', event)
time.sleep(1)
print('Done')
# Update all pending events
self.update()
self.update_idletasks()
# Release event handler
self.event_running = False
return
# Button
self.button = tk.Button(
master=self,
text='Test',
command=event_handler
)
self.button.grid()
self.bind('<Left>', event_handler)
self.focus()
if __name__ == "__main__":
root = tk.Tk()
root.title("TestTool")
# Start application
app = App(root)
app.pack(fill="both", expand=True)
root.mainloop()