Validating user input

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

none

This is the default mode. No validation occurs if validate is set to "none"

focus

When validate is set to "focus", the validate command is called twice; once when the widget receives focus and once when the focus is lost

focusin

The validate command is called when the widget receives focus

focusout

The validate command is called when the widget loses focus

key

The validate command is called when the entry is edited

all

The validate command is called in all the above cases

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

%d

Type of action that occurred on the widget—1 for insert, 0 for delete, and -1 for focus, forced, or textvariable validation.

%i

Index of char string inserted or deleted, if any, else it will be -1.

%P

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.

%s

The current value of entry, prior to editing.

%S

The text string being inserted/deleted, if any, {} otherwise.

%v

The type of validation currently set.

%V

The type of validation that triggered the callback method (key, focusin, focusout, and forced).

%W

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):

Tip

Take particular note of data returned by %P and %s, because they pertain to the actual data entered by the user in the Entry widget.

In most cases, you will be checking either of these two data against your validation rules.

Now that we have a background of rules of data validation, let's see two practical examples that demonstrate input validation.

Key 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:

Key Validation

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:

  • We first register two options validatecommand (vcmd) and invalidcommand (invcmd).
  • In our example, validatecommand is registered to call the validate_data method, and the invalidcommand option is registered to call another method named invalid_name.
  • The 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.
  • If the validate method returns 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.

Note

Let's look at the code register(self, func, subst=None, needcleanup=1).

The register method returns a newly created Tcl function. If this function is called, the Python function func is executed. If an optional function subst is provided it is executed before func.

Focus Out Validation

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.

Focus Out Validation

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:

  • The validate mode is set to '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.
  • This program uses data provided by the %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 program uses regular expressions to check if the entered value corresponds to a valid e-mail format. Validation usually relies on regular expressions and a whole lot of explanation to cover this topic, but it is out of the scope of this project and the book. For more information on regular expression modules, visit the following link:

    http://docs.python.org/2/library/re.html

This concludes our discussion on input validation in Tkinter. Hopefully, you should now be able to implement input validation to suit your custom needs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.79.84