Reputation: 13
Input or paste only a float into a tk.Entry
, except allowing an empty field, then trigger an action that passes the updated value. This should be generalizable.
import tkinter as tk
def float_validation(inStr,acttyp): #check for float
if acttyp == '1':
try:
float(inStr)
return True
except ValueError:
return False
#Do NOT evaluate actype == '0' (delete action)
#Using acttype == '0', try:float("") returns False
return True
def update_from_entry(entry): #address empty string after float validation
if not entry.get() == "":
vals[strs.index(entry)].set(float(entry.get()))
else:
vals[strs.index(entry)].set(0)
def calculate(entry): #do something after entry update
update_from_entry(entry)
calculated_value.set(entry1_val.get()+entry2_val.get())
root = tk.Tk()
strs = [] #create lists of objects to index against each other
vals = []
entry1_str = tk.StringVar(value='0.123')
strs.append(entry1_str)
entry1_str.trace_add('write',lambda a,b,c, entry=entry1_str: calculate(entry))
entry1_input = tk.Entry(root, textvariable=entry1_str, validate='all')
entry1_input.grid(row=0,sticky='ew')
entry1_input['validatecommand'] = entry1_input.register(float_validation),'%P','%d'
entry1_val = tk.DoubleVar(value = float(entry1_str.get()))
vals.append(entry1_val)
entry2_str = tk.StringVar(value='0.456')
strs.append(entry2_str)
entry2_str.trace_add('write',lambda a,b,c,entry=entry2_str:calculate(entry))
entry2_input = tk.Entry(root, textvariable=entry2_str, validate='all')
entry2_input.grid(row=1,sticky='ew')
entry2_input['validatecommand'] = entry1_input.register(float_validation),'%P','%d'
entry2_val = tk.DoubleVar(value = float(entry2_str.get()))
vals.append(entry2_val)
calculated_value = tk.DoubleVar(value=entry1_val.get()+entry2_val.get())
output = tk.Label(root, textvariable=calculated_value).grid(row=2,sticky='ew')
root.mainloop()
The code works, but is it over-contrived? Is this a reasonable way of limiting the tk.Entry
to a float by introducing additional steps to address an empty tk.Entry
validation of False
from float("")
, while triggering updates? Have I misunderstood how to allow empty (and/or pasting into) tk.Entry
objects?
Upvotes: 0
Views: 53
Reputation: 3824
Validating floats in Entry
has a few edge cases apart from ""
.
If negative numbers are concerned '-' needs to be accepted. If '.123' is valid '.' must be accepted. If exponents are accepted '{valid-decimal}E' and '{valid-decimal}e-' must be accepted.
import tkinter as tk
def to_float( str_in ):
""" Converts str_in to a float if possible.
Possible intermediate steps entering a float:
It accepts "", '.', '-' and '-.' returning zero
It accepts 'digits{Ee}' and 'digits{eE}-' returning digits
If str_in doesn't convert to a float it raises a ValueError
"""
str_in = str_in or '0' # Changes str_in to '0' if it starts as ""
# Remove this block if these edge cases aren't a concern.
if str_in[-1] in [ '-', '.', 'e', 'E' ] : # if last character is in the list
str_in += '0'
# '-0', '.0', '-.0', '0E0' and '0E-0' are valid floats ( 0.0 )
return float( str_in )
def float_valid( str_in ):
try:
to_float( str_in )
return True
except ValueError:
return False
root = tk.Tk()
validate_cmd = root.register( float_valid )
v1 = tk.StringVar()
v2 = tk.StringVar()
result = tk.StringVar( value = '0.0' )
e1 = tk.Entry( root, validate = 'all', validatecommand = (validate_cmd, '%P'),
textvariable = v1 )
e2 = tk.Entry( root, validate = 'all', validatecommand = (validate_cmd, '%P'),
textvariable = v2 )
res = tk.Label( root, textvariable = result )
def calc( *args ):
result.set( to_float( v1.get() ) + to_float( v2.get() ) )
v1.trace( 'w', calc )
v2.trace( 'w', calc )
e1.grid( row = 0, column = 0, padx = 5, pady = 5 )
e2.grid( row = 0, column = 1, padx = 5, pady = 5 )
res.grid( row = 1, column = 0, columnspan = 2, padx = 5, pady = 5 )
root.mainloop()
Upvotes: 0