Attempts to keep the function running while holding down the tkinter button
I currently have a button in tkinter that runs a function when the button is released. I need buttons to be constantly added to a number at a certain rate throughout the holding of the button.
global var
var=1
def start_add(event,var):
global running
running = True
var=var+1
print(var)
return var
def stop_add(event):
global running
print("Released")
running = False
button = Button(window, text ="Hold")
button.grid(row=5,column=0)
button.bind('<ButtonPress-1>',start_add)
button.bind('<ButtonRelease-1>',stop_add)
I don’t necessarily need to run any function when the button is released, just run while holding down the button if it helps. Any help is greatly appreciated.
Solution
There’s no built-in thing to do this, but making your own Button can be easy. You’re also on the right track, the only thing you’re missing is that you need to use after
to make loops and after_cancel
to stop loops:
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class PaulButton(tk. Button):
"""
a new kind of Button that calls the command repeatedly while the Button is held
:command: the function to run
:timeout: the number of milliseconds between :command: calls
if timeout is not supplied, this Button runs the function once on the DOWN click,
unlike a normal Button, which runs on release
"""
def __init__(self, master=None, **kwargs):
self.command = kwargs.pop('command', None)
self.timeout = kwargs.pop('timeout', None)
tk. Button.__init__(self, master, **kwargs)
self.bind('<ButtonPress-1>', self.start)
self.bind('<ButtonRelease-1>', self.stop)
self.timer = ''
def start(self, event=None):
if self.command is not None:
self.command()
if self.timeout is not None:
self.timer = self.after(self.timeout, self.start)
def stop(self, event=None):
self.after_cancel(self.timer)
#demo code:
var=0
def func():
global var
var=var+1
print(var)
root = tk. Tk()
btn = PaulButton(root, command=func, timeout=100, text="Click and hold to repeat!")
btn.pack(fill=tk. X)
btn = PaulButton(root, command=func, text="Click to run once!")
btn.pack(fill=tk. X)
btn = tk. Button(root, command=func, text="Normal Button.")
btn.pack(fill=tk. X)
root.mainloop()
As mentioned in @rioV8, the after()
call is not very accurate. If you set the timeout to 100 milliseconds, you can typically expect an interval of 100 – 103 milliseconds between calls. The longer you hold down the button, the more these errors accumulate. If you want to accurately calculate when a button is pressed, you need a different method.