I want to create a small virtual joystick with tkinter
, so I need correct handling of long press of buttons.
I’ve created a code like this:
import tkinter as tk
def up():
print("Up")
up_button.config(image=up_active_image)
def reset_up(event):
print("Up released")
up_button.config(image=up_image)
root = tk.Tk()
frame = tk.Frame(root)
frame.grid(row=0, column=0)
up_image = tk.PhotoImage(file="assets/up.png")
up_active_image = tk.PhotoImage(file="assets/up_active.png")
up_button = tk.Label(frame, image=up_image)
up_button.grid(row=0, column=1)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.bind('<Up>', lambda event: up())
root.bind('<KeyRelease-Up>', reset_up)
root.mainloop()
But when I press arrow-up for a long time I receive this output:
Up
Up release
Up
Up release
Up
Up release
Up
Up release
Up
Up release
...
While I’m expecting just one line with word up
What am I doing wrong? How to fix this problem?
3
A simplistic approach would be to use a variable to store a Boolean flag that gets set when Up
is pressed, and reset when it’s released. You can set the flag as soon as the button press event is detected, and use it to ignore subsequent firings of the event caused by key repeats while Up
is being held.
import tkinter as tk
def up():
if not upvar.get(): # if the flag isn't set yet
upvar.set(True) # set the flag
up_button.config(image=up_active_image)
print("Up")
def reset_up(event):
upvar.set(False) # reset the flag
up_button.config(image=up_image)
print("Up released")
root = tk.Tk()
upvar = tk.BooleanVar(root, False) # set up a variable to store the button press flag
frame = tk.Frame(root)
frame.grid(row=0, column=0)
up_image = tk.PhotoImage(file="assets/up.png")
up_active_image = tk.PhotoImage(file="assets/up_active.png")
up_button = tk.Label(frame, image=up_image)
up_button.grid(row=0, column=1)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.bind('<Up>', lambda event: up())
root.bind('<KeyRelease-Up>', reset_up)
root.mainloop()
Note that I’ve used a tk.BooleanVar
instance to store the flag value, but you could also use a global
variable
I also had to remove the image-related stuff to get this code to run, since I don’t have those assets…but you get the idea.
4