Interactively validating Entry widget content in tkinter Interactively validating Entry widget content in tkinter python python

Interactively validating Entry widget content in tkinter


The correct answer is, use the validatecommand attribute of the widget. Unfortunately this feature is severely under-documented in the Tkinter world, though it is quite sufficiently documented in the Tk world. Even though it's not documented well, it has everything you need to do validation without resorting to bindings or tracing variables, or modifying the widget from within the validation procedure.

The trick is to know that you can have Tkinter pass in special values to your validate command. These values give you all the information you need to know to decide on whether the data is valid or not: the value prior to the edit, the value after the edit if the edit is valid, and several other bits of information. To use these, though, you need to do a little voodoo to get this information passed to your validate command.

Note: it's important that the validation command returns either True or False. Anything else will cause the validation to be turned off for the widget.

Here's an example that only allows lowercase. It also prints the values of all of the special values for illustrative purposes. They aren't all necessary; you rarely need more than one or two.

import tkinter as tk  # python 3.x# import Tkinter as tk # python 2.xclass Example(tk.Frame):    def __init__(self, parent):        tk.Frame.__init__(self, parent)        # valid percent substitutions (from the Tk entry man page)        # note: you only have to register the ones you need; this        # example registers them all for illustrative purposes        #        # %d = Type of action (1=insert, 0=delete, -1 for others)        # %i = index of char string to be inserted/deleted, or -1        # %P = value of the entry if the edit is allowed        # %s = value of entry prior to editing        # %S = the text string being inserted or deleted, if any        # %v = the type of validation that is currently set        # %V = the type of validation that triggered the callback        #      (key, focusin, focusout, forced)        # %W = the tk name of the widget        vcmd = (self.register(self.onValidate),                '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')        self.entry = tk.Entry(self, validate="key", validatecommand=vcmd)        self.text = tk.Text(self, height=10, width=40)        self.entry.pack(side="top", fill="x")        self.text.pack(side="bottom", fill="both", expand=True)    def onValidate(self, d, i, P, s, S, v, V, W):        self.text.delete("1.0", "end")        self.text.insert("end","OnValidate:\n")        self.text.insert("end","d='%s'\n" % d)        self.text.insert("end","i='%s'\n" % i)        self.text.insert("end","P='%s'\n" % P)        self.text.insert("end","s='%s'\n" % s)        self.text.insert("end","S='%s'\n" % S)        self.text.insert("end","v='%s'\n" % v)        self.text.insert("end","V='%s'\n" % V)        self.text.insert("end","W='%s'\n" % W)        # Disallow anything but lowercase letters        if S == S.lower():            return True        else:            self.bell()            return Falseif __name__ == "__main__":    root = tk.Tk()    Example(root).pack(fill="both", expand=True)    root.mainloop()

For more information about what happens under the hood when you call the register method, see Why is calling register() required for tkinter input validation?

For the canonical documentation see the Validation section of the Tcl/Tk Entry man page


After studying and experimenting with Bryan's code, I produced a minimal version of input validation. The following code will put up an Entry box and only accept numeric digits.

from tkinter import *root = Tk()def testVal(inStr,acttyp):    if acttyp == '1': #insert        if not inStr.isdigit():            return False    return Trueentry = Entry(root, validate="key")entry['validatecommand'] = (entry.register(testVal),'%P','%d')entry.pack()root.mainloop()

Perhaps I should add that I am still learning Python and I will gladly accept any and all comments/suggestions.


Use a Tkinter.StringVar to track the value of the Entry widget. You can validate the value of the StringVar by setting a trace on it.

Here's a short working program that accepts only valid floats in the Entry widget.

try:    from tkinter import *except ImportError:    from Tkinter import *  # Python 2root = Tk()sv = StringVar()def validate_float(var):    new_value = var.get()    try:        new_value == '' or float(new_value)        validate_float.old_value = new_value    except:        var.set(validate_float.old_value)validate_float.old_value = ''  # Define function attribute.# trace wants a callback with nearly useless parameters, fixing with lambda.sv.trace('w', lambda nm, idx, mode, var=sv: validate_float(var))ent = Entry(root, textvariable=sv)ent.pack()ent.focus_set()root.mainloop()