Tkinter Unbinding Key Event Issue
Solution 1:
Here is a solution that takes the focus away from the widget, so the binding wont get triggered:
import winsound
from tkinter import *
def beep(event):
dummy.focus_set() #setting focus to dummy
winsound.Beep(440, 1000) #playing it
root.after(1000,frame.focus_set) #setting focus back after playing for 1000 ms
root = Tk()
dummy = Label() #making a dummy widget
dummy.pack()
frame = Frame(root, width=100, height=100)
frame.bind("<space>",beep)
frame.pack()
frame.focus_set()
root.mainloop()
I've commented it to understand better, but this is just a way around and its not that complicated to understand either.
Also keep in mind, in all cases of using winsound
, as long as that beep has started and finished playing, the GUI will be unresponsive, that is, GUI will be unresponsive for 1 sec(in your case).
Solution 2:
This should fix it however you have to download keyboard
module with pip install keyboard
:
import winsound
from tkinter import *
import keyboard
from _thread import start_new_thread
def beep():
while True:
if keyboard.is_pressed('space'):
winsound.Beep(440, 1000)
root = Tk()
frame = Frame(root, width=100, height=100)
start_new_thread(beep, ())
frame.pack()
frame.focus_set()
root.mainloop()
First start_new_thread()
(syntax is important) makes beep()
threaded (runs in background?) and its a while
loop so it runs continuously and whenever you press space it will beep
and even if you spam space it will still just run one beep
. However there is a downside. It will run while script is not terminated so if you focus out it will still beep if you press spacebar
Solution 3:
You can use the elapsed time since the last successful keypress
to decide if the beep should be produced or not.
maybe like this: I do not have access to winsound, so I am using an os
feature to mimic a beep. You can comment this out, and uncomment the calls to winsound
# import winsoundimport os
import tkinter as tk
import time
defbeep(e, time_limit=1, timer=[0]):
t0 = timer[0]
t1 = time.time()
delta_t = t1 - t0
if delta_t < time_limit:
return# winsound.Beep(440, 1000)
os.system('say "Beep"')
timer[0] = t1
root = tk.Tk()
frame = tk.Frame(root, width=100, height=100)
frame.bind("<space>", beep)
frame.pack()
frame.focus_set()
root.mainloop()
Solution 4:
You can bind back the event via after_idle()
:
defbeep(e):
e.widget.unbind('<space>')
winsound.Beep(440, 1000)
e.widget.after_idle(e.widget.bind, '<space>', beep)
explanation:
The callback passed to after_idle()
will be executed when tkinter mainloop
is idle, i.e. no pending works/events to be handled. So if the spacebar is pressed many times, the first press triggers beep()
in which tkinter
unbinds the event, beep and then schedules the rebind. After beep()
returns, tkinter
keeps handling the pending tasks, i.e. handle the rest spacebar events (but at that moment, no bind is active) and then do the after_idle
schedule task which is the rebind.
Post a Comment for "Tkinter Unbinding Key Event Issue"