问题
I am creating a date of birth entry form for my application, and want to make it so that they can only enter numbers, and to limit the numbers inputted to the maximum amount needed e.g. 2 for day. When I tried to implement this, it doesn't even let me do anything in the entry widgets. How can I limit the character length and only accept numbers?
def onlyNumbers(char):
if (len(dayE.get()) >= 2):
return False
elif (len(monthE.get()) >= 2):
return False
elif (len(yearE.get()) >= 4):
return False
elif (char is ""):
return True
else:
return char.isdigit()
dayV = tk.StringVar(self, value = "DD")
monthV = tk.StringVar(self, value = "MM")
yearV = tk.StringVar(self, value = "YYYY")
validation = self.register(onlyNumbers)
dayE = tk.Entry(self, font = BASIC_FONT, textvariable = dayV, width = 5, justify = "center")
dayE.pack()
dayE.config(validate = "key", validatecommand = (validation, "%P"))
monthE = tk.Entry(self, font = BASIC_FONT, textvariable = monthV, width = 5, justify = "center")
monthE.pack()
monthE.config(validate = "key", validatecommand = (validation, "%P"))
yearE = tk.Entry(self, font = BASIC_FONT, textvariable = yearV, width = 5, justify = "center")
yearE.pack()
yearE.config(validate = "key", validatecommand = (validation, "%P"))
回答1:
Question:
Entry
validation, to limit the character length and only allow numbers
This example implements:
- Allow only input of digits
- Limit number of digits according to
'DD', 'MM', 'YYYY'
- Allow leading zeros in
'DD', 'MM'
- Allow only ranges of numbers,
1, 31
,1, 12
and argumentyears=(<from>, <to>)
- Returns the edited data as:
{'month': 3, 'day': 28, 'year': 2020}
Reference:
VALIDATION
Validation works by setting the
validatecommand=
option to a script (validateCommand) which will be evaluated according to thevalidate=
option.
Explanation of the used percent substitutions ('%W', '%V', '%v', '%P', '%S'
)SO:interactively-validating-entry-widget-content-in-tkinter
Be aware of the note there:
Note: it's important that the validation command returns eitherTrue
orFalse
. Anything else will cause the validation to be turned off.
Note:
The validation get turned OFF, if the Entry
text get changed, either using .insert(...
, .delete(...
or <textvariable>.set(...)
.
import tkinter as tk
class DateEntry(tk.Frame):
def __init__(self, parent, **kwargs):
years = kwargs.pop('years', (1900, 9999))
super().__init__(parent, **kwargs)
vcmd = (self.register(self._validate), '%W', '%V', '%v', '%P', '%S')
for name, text, v1, v2 in (('day', 'DD', 1, 31),
('month', 'MM', 1, 12),
('year', 'YYYY', years[0], years[1])):
e = tk.Entry(self, name=name, width=len(text) + 1, justify="center")
e.pack(side=tk.LEFT)
e.insert(0, text)
e._valid = (len(text), v1, v2)
e.config(validate="all", validatecommand=vcmd)
def get(self):
data = {}
for entry in [self.nametowidget(child) for child in self.children]:
text = entry.get()
data[entry.winfo_name()] = int(text) if text.isdigit() else None
return data
def _validate(self, widget, cmd, validate, value, text):
# get this entry reference
w = self.nametowidget(widget)
# Clear entry or do nothing
if cmd in ('focusin', 'forced') or value == '':
if not value.isdigit():
w.delete(0, tk.END)
# Set the 'validate' option again after edit
w.after_idle(w.config, {'validate': validate})
return True
# process key
elif cmd == 'key' and value.isdigit():
# get from this entry the valid parameter
l, v1, v2 = w._valid
# get the startswith chars if YYYY
if v1 > 1 and len(value) < l:
l2 = len(value)
v1, v2 = int(str(v1)[:l2]), int(str(v2)[:l2])
# allow leading zero in DD / MM
elif v1 == 1 and len(value) == 1 and int(value) == 0:
return True
# return True if all valid else False
return all((text.isdigit(), v1 <= int(value) <= v2, len(value) <= l))
# else return False
return False
Usage:
class App(tk.Tk):
def __init__(self):
super().__init__()
tk.Button(self, text='print date', command=self.print_date).grid()
self.date_entry = DateEntry(self, years=(2000, 2020))
self.date_entry.grid()
def print_date(self):
print('print_date: {}'.format(self.date_entry.get()))
# >>> print_date: {'month': 3, 'day': 28, 'year': 2020}
if __name__ == "__main__":
App().mainloop()
Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6
来源:https://stackoverflow.com/questions/60890142/how-do-i-get-this-validation-code-to-limit-the-character-length-and-only-allow-n