Let's now discuss input data validation.
Most of the applications we have developed in our book are point and click-based (drum machine, chess, drawing application), where validation of user input is not required.
However, data validation is a must in programs like our phonebook application, where the user enters some data, and we store it in a database.
Ignoring the user input validation can be dangerous in such applications because input data can be misused for SQL injection. In general, any application where an user can enter textual data, is a good candidate for validating user input. In fact, it is almost considered a maxim not to trust user inputs.
A wrong user input may be intentional or accidental. In either case, if you fail to validate or sanitize the data, you may cause unexpected error in your program. In worst cases, user input can be used to inject harmful code that may be capable of crashing a program or wiping out an entire database.
Widgets such as Listbox, Combobox, and Radiobuttons allow limited input options, and hence, cannot normally be misused to input wrong data. On the other hand, widgets such as Entry widget, Spinbox widget, and Text widget allow a large possibility of user inputs, and hence, need to be validated for correctness.
To enable validation on a widget, you need to specify an additional option of the form validate = 'validationmode'
to the widget.
For example, if you want to enable validation on an entry widget, you begin by specifying the validate option as follows:
Entry( root, validate="all", validatecommand=vcmd)
The validation can occur in one of the following validation modes:
Validation Mode |
Explanation |
---|---|
This is the default mode. No validation occurs if | |
When | |
The | |
The | |
The | |
The |
The code of the 8.03 validation mode demo.py
file demonstrates all these validation modes by attaching them to a single validation method. Note the different ways different Entry widgets respond to different events. Some Entry widgets call the validation method on focus events while others call the validation method at the time of entering key strokes into the widget, while still others use a combination of focus and key events.
Although we did set the validation mode to trigger the validate
method, we need some sort of data to validate against our rules. This is passed to the validate
method using percent substitution. For instance, we passed the mode as an argument to our validate
method by performing a percent substitution on the validate
command, as shown in the following:
vcmd = (self.root.register(self.validate), '%V')
We followed by passing the value of v
as an argument to our validate method:
def validate(self, v)
In addition to %V
, Tkinter recognizes the following percent substitutions:
Percent substitutions |
Explanation |
---|---|
Type of action that occurred on the widget— | |
Index of | |
The value of the entry if the edit is allowed. If you are configuring the Entry widget to have a new textvariable, this will be the value of that textvariable. | |
The current value of entry, prior to editing. | |
The text string being inserted/deleted, if any, | |
The type of validation currently set. | |
The type of validation that triggered the callback method (key, focusin, focusout, and forced). | |
The name of the Entry widget. |
These validations provide us with the necessary data we can use to validate the input.
Let's now pass all these data and just print them through a dummy validate
method just to see the kind of data we can expect to get for carrying out our validations (refer to the code of 8.04 percent substitutions demo.py
):
Now that we have a background of rules of data validation, let's see two practical examples that demonstrate input validation.
Let's assume that we have a form that asks for a user's name. We want the user to input only alphabets or space characters in the name. Thus, any number or special character is not to be allowed, as shown in the following screenshot of the widget:
This is clearly a case of 'key'
validation mode, because we want to check if an entry is valid after every key press. The percent substitution that we need to check is %S
, because it yields the text string being inserted or deleted in the Entry widget. Accordingly, the code that validates the entry widget is as follows (refer to 8.05 key validation.py
):
import Tkinter as tk class KeyValidationDemo(): def __init__(self): root = tk.Tk() tk.Label(root, text='Enter your name').pack() vcmd = (root.register(self.validate_data), '%S') invcmd = (root.register(self.invalid_name), '%S') tk.Entry(root, validate="key", validatecommand=vcmd,invalidcommand=invcmd).pack(pady=5, padx=5) self.errmsg = tk.Label(root, text= '', fg='red') self.errmsg.pack() root.mainloop() def validate_data(self, S): self.errmsg.config(text='') return (S.isalpha() or S =='') # always return True or False def invalid_name(self, S): self.errmsg.config(text='Invalid characters name canonly have alphabets'%S) app= KeyValidationDemo()
The description of the preceding code is as follows:
validatecommand
(vcmd
) and invalidcommand
(invcmd
).validatecommand
is registered to call the validate_data
method, and the invalidcommand
option is registered to call another method named invalid_name
.validatecommand
option specifies a method to be evaluated which would validate the input. The validation method must return a Boolean value, where a True
signifies that the data entered is valid, and a False
return value signifies that data is invalid.False
(invalid data), no data is added to the Entry widget and the script registered for invalidcommand
is evaluated. In our case, a False
validation would call the invalid_name
method. The invalidcommand
method is generally responsible for displaying error messages or setting back the focus to the Entry widget.The previous example demonstrated validation in 'key'
mode. This means that the validation method was called after every key press to check if the entry was valid.
However, there are situations when you might want to check the entire string entered into the widget, rather than checking individual key stroke entries.
For example, if an Entry widget accepts a valid e-mail address, we would ideally like to check the validity after the user has entered the entire e-mail address, and not after every key stroke entry. This would qualify as validation in 'focusout'
mode.
Check out the code of 8.06 focus out validation.py
for a demonstration on e-mail validation in the focusout
mode:
import Tkinter as tk import re class FocusOutValidationDemo(): def __init__(self): self.master = tk.Tk() self.errormsg = tk.Label(text='', fg='red') self.errormsg.pack() tk.Label(text='Enter Email Address').pack() vcmd = (self.master.register(self.validate_email), '%P') invcmd = (self.master.register(self.invalid_email), '%P') self.emailentry = tk.Entry(self.master, validate ="focusout", validatecommand=vcmd, invalidcommand=invcmd) self.emailentry.pack() tk.Button(self.master, text="Login").pack() tk.mainloop() def validate_email(self, P): self.errormsg.config(text='') x = re.match(r"[^@]+@[^@]+.[^@]+", P) return (x != None)# True(valid email)/False(invalid email) def invalid_email(self, P): self.errormsg.config(text='Invalid Email Address') self.emailentry.focus_set() app = FocusOutValidationDemo()
The description of the preceding code is as follows:
The code has a lot of similarities to the previous validation example. However, note the following differences:
'focusout'
in contrast to the 'key'
mode in the previous example. This means that the validation would be done only when the Entry widget loses focus
.%P
percentage substitution, in contrast to %S
, as used in the previous example. This is understandable as %P
provides the value entered in the Entry widget, but %S
provides the value of the last key stroke.This concludes our discussion on input validation in Tkinter. Hopefully, you should now be able to implement input validation to suit your custom needs.
3.147.79.84