I am having an issue validating spinbox input. I have a workaround below that seems to work; however, it's awkward. Assuming this isn't a bug, is there a correct way to do this? I am using Anaconda Python 3.6 (tk 8.6) on Windows 10.
The issue is that validate
is set to None
if you return False
from the validation function when the value in the spinbox entry is between to
and from
. This only occurs when clicking the up or down buttons and not when directly editing the text.
import tkinter as tk
class SpinboxGui:
def __init__(self):
self.root = tk.Tk()
vcmd = (self.root.register(self.validate_spin), '%W', '%P')
self.spin = tk.Spinbox(self.root, from_=0, to=50000)
self.spin.config(validate="key", validatecommand=vcmd)
self.spin.pack()
def validate_spin(self, name, nv):
try:
print(nv)
n = int(nv)
except:
return False
if n <= 15000:
return True
return False
if __name__ == "__main__":
SpinboxGui()
tk.mainloop()
To reproduce, highlight 0 and type 149999. Then click up a few times. Note that the validation command stops being called. Output is:
01
014
0149
01499
014999
0149999
15000
15001
Now, according to the docs, using textVariable
and validateCommand
together is dangerous; indeed, I have crashed Python/Tkinter in more ways than one. However, in this case, it doesn't matter whether you use textVariable
or not; the problem is the same.
One possible solution might be to edit the to
and from
options in the validation function. Even if this works, it's somewhat problematic for me because I'm syncing spinbox values to an embedded Matplotlib plot. I would need to compute to
and from
and convert units for each Matplotlib Artist and spinbox.
Since you can't edit the textVariable
in the validation function, what I came up with is the following. Maybe someone can improve on this.
def __init__(self):
# http://stackoverflow.com/a/4140988/675216
vcmd= (self.root.register(self.validate_spin), '%W', '%P')
# Rest of code left out
self.spin.config(validate="key", validatecommand=vcmd)
self.spin.bind("<<ResetValidate>>", self.on_reset_validate)
def on_reset_validate(self, event):
# Turn validate back on and set textVariable
self.spin.config(validate="key")
def validate_spin(self, name, nv):
# Do validation ...
if not valid:
self.spin.event_generate("<<ResetValidate>>", when="tail")
return valid