You can bind functions to keystroke events with root.bind(event, callback).
If you are using Linux or Mac, root.overrideredirect(True) will
prevent your application from receiving keystroke events. You can read
more here: Tkinter's overrideredirect prevents certain events in Mac and Linux
Example:
def keydown(e):
print(f"Key pressed: ")
print("Key code:", e.keycode)
print("Key symbol:", e.keysym)
print("Char:", e.char)
def keyup(e):
print(f"Key '{e}' released")
root.bind("<KeyPress>", keydown)
root.bind("<KeyRelease>", keyup)
root.focus_set()
Alternatively, you can also bind to specific keys with <Key-KEYSYM>, e.g. <Key-space> for the spacebar. A list with all keysyms can be found here
Some more events are listed here
Implementation example
Here is an example with a custom CountdownLabel class that is derived from tkinter.Label and automatically binds to the spacebar key event.
app.py
from countdown import CountdownLabel
from tkinter import Frame, StringVar, Tk, Button
root = Tk()
root.geometry("120x60")
root.lift()
root.wm_attributes("-topmost", True)
root.resizable(0, 0)
# Not supported on Linux and MacOS
# root.overrideredirect(True)
# root.wm_attributes("-disabled", True)
# root.wm_attributes("-transparentcolor", "white")
timer_display = CountdownLabel(root, 10, 5)
timer_display.pack(fill="both", expand=True)
timer_display.configure(background="white")
timer_display.configure(font=('Trebuchet MS', 26, 'bold'))
timer_display.focus_set()
root.mainloop()
countdown.py
from tkinter import Label
class CountdownLabel(Label):
# context : A reference to the Label in order to change the text and
# to close it later on
# duration: Total time in seconds
# critical: Length of the last timespan before the countdown finishes
# in seconds
def __init__(self, context, duration, critical):
super().__init__(context)
self.duration = duration
self.critical = critical if duration >= critical else duration
self.update_ui()
self.bound_sequence = "<Key-space>"
self.bound_funcid = self.bind(self.bound_sequence, self.get_handler())
# Returns a function for the event binding that still has access to
# the instance variables
def get_handler(self):
# Gets executed once when the counter starts through handler() and calls
# itself every second from then on to update the GUI
def tick():
self.after(1000, tick)
self.update_ui()
self.duration -= 1
# Gets executed when time left is less than <critical> (default = 10s)
# Sets the font color to red
def change_font_color():
self.configure(foreground="red")
# Destroys itself after the countdown finishes
self.after((self.critical + 1) * 1000, lambda : self.destroy())
def handler(event):
self.unbind(self.bound_sequence, self.bound_funcid)
self.bound_funcid = -1
self.bound_sequence = None
self.after((self.duration - self.critical) * 1000, change_font_color)
tick()
return handler
# Updates the displayed time in the label
def update_ui(self):
mm = self.duration // 60
ss = self.duration % 60
self.config(text="%02d:%02d" % (mm, ss))
def change_binding(self, sequence):
if self.bound_funcid > 0:
self.unbind(self.bound_sequence, self.bound_funcid)
self.bound_sequence = sequence
self.funcid = self.bind(self.bound_sequence, self.get_handler())