Tkinter Wiki   ValidateEntry UserPreferences
 
HelpContents FindPage Diffs Info Edit Subscribe XML Print View

The ValidateEntry widget, described on Fredrik Lundh's page on [WWW]Validating Entry Widget, can be used to confirm that the value that the user enters is what you, the programmer, wanted. Fredrik's example code doesn't show you how to retrieve the data entered by the user (use a ?StringVar called self.results), but the example below does. If you want to use the widget as a module that you import, you'll have to do a little more work.

Another approach to entry validation is provided in Chapter 6 of [WWW]Grayson's book on Tkinter. His example 6-17 spells out the details.

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 97 
 98 
 99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
'''
Info by Fredrik Lundh:
This module implements a validating version of the Tkinter Entry widget.
It uses the textvariable option to attach a StringVar to the widget,
and uses the variable trace function to keep track of what's going on (in real time, as the user types the input).
To specify how validation is to be done, override the validate method.
Note that the constructor takes a parent widget, and also allows you to use the value option to specify the initial contents.
All other options are passed on to the Entry widget itself.
'''

from Tkinter import *

class ValidatingEntry(Entry):
    # base class for validating entry widgets

    def __init__(self, master, value="", **kw):
        apply(Entry.__init__, (self, master), kw)
        self.__value = value
        self.__variable = StringVar()
        self.__variable.set(value)
        self.__variable.trace("w", self.__callback)
        self.config(textvariable=self.__variable)
        self.results = StringVar()
        if self.__value is None: self.results.set(None)
        else:
                self.results.set(self.__value)

    def __callback(self, *dummy):
        value = self.__variable.get()
        newvalue = self.validate(value)
        if newvalue is None:
            self.__variable.set(self.__value)
        elif newvalue != value:
            self.__value = newvalue
            self.__variable.set(newvalue)
        else:
            self.__value = value

    def validate(self, value):
        # override: return value, new value, or None if invalid
        self.results.set(value)
        return value

    def getresults(self, value):
        # override: return value, or chopped value in the case of ChopLengthEntry
        return self.results.get()

'''
The first two examples are subclasses that check that the input is a valid Python integer or float, respectively.
The validate method simply tries to convert the value to an object of the right kind, and returns None (reject) if that fails.
'''

class IntegerEntry(ValidatingEntry):
    def validate(self, value):
        try:
            if value:
                v = int(value)
                self.results.set(value)
            return value
        except ValueError:
            return None


class FloatEntry(ValidatingEntry):
    def validate(self, value):
        try:
            if value:
                v = float(value)
                self.results.set(value)
            return value
        except ValueError:
            return None


class MaxLengthEntry(ValidatingEntry):
    '''MaxLength is a subclass that restricts the length of the input to a given max length.
       The getresults method is provided only to deal with a situation where a too-long
       initial value is provided, and the user accepts it without editing.
       Also if a too-long initial value is provided, it must be truncated to at least one char
       less than the max length, or else the user will be unable to even edit it
       (since the Del or BS key would cause the length to exceed the maxlength, they would be ignored)'''
    def __init__(self, master, value="", maxlength=None, **kw):
        if len(value) > maxlength-1:
                value = value[:maxlength-1]
        args = {'value': value}
        self.maxlength = maxlength
        apply(ValidatingEntry.__init__, (self, master), args)

    def validate(self, value):
        if self.maxlength is None or len(value) <= self.maxlength:
                self.results.set(value)
                return value
        return None # new value too long

    def getresults(self, value):
        if self.maxlength:
                if len(value) > self.maxlength:
                        value = value[:self.maxlength]
                        self.results.set(value)
        return self.results.get()

class ChopLengthEntry(ValidatingEntry):
    '''ChopLengthEntry accepts all entries, but chops them when the results are called for'''
    def __init__(self, master, value="", maxlength=None, **kw):
        args = {'value': value}
        self.maxlength = maxlength
        apply(ValidatingEntry.__init__, (self, master), args)

    def getresults(self, value):
        if self.maxlength:
                if len(value) > self.maxlength:
                        value = value[:self.maxlength]
                        self.results.set(value)
        return self.results.get()


class StringEntry(ValidatingEntry):
        #same as ValidatingEntry; nothing extra
        pass

if __name__ == '__main__':
        labelString = ['Integer','Float','String','MaxLength','ChopLength']
        limitString = ['MaxLength','ChopLength']
        initial     = [123, 456.789, '"hello, world!"', '"long text"', '"Please don\'t cut me!"']
        num = len(labelString)

        entry = []; value = []
        for i in range(0,num):
                entry.append(None)
                value.append(None)

        def results():
                resultsList = []
                for i in range(0,num):
                        value[i] = entry[i].results.get()
                        value[i] = entry[i].getresults(value[i])
                        if value[i] is not None:
                                resultsList.append( value[i] )
                for i in range(len(resultsList)):
                        print "validated %s entry is: %s" % (labelString[i],resultsList[i] )
                root.destroy()

        root = Tk()
        lab = []; but = []; entry = []
        #if we put the names of the various widget into a list, we can create instances
        #  using a for loop. Note that we need to handle
        #  the special case that 2 of them have a 2nd argument, while the others don't
        # (alternatively, could have re-defined the widgets to all take a (sometimes unneeded) 2nd argument)
        for i in range(0, num):
                lab.append(None); but.append(None); entry.append(None)
                lab[i] = Label(text = 'please enter a '+labelString[i])
                lab[i].pack(side='top')
                txt = "%sEntry(root,value=%s)" % (labelString[i],str(initial[i]))
                if labelString[i] in limitString:
                        maxLength = "10"
                        txt = "%sEntry(root,value=%s, maxlength=%s)" % (labelString[i],str(initial[i]),maxLength)
                entry[i] = eval(txt)
                entry[i].pack()

        bt = Button(text = 'Ok', command = results)
        bt.pack(side='left')
        cn = Button(text = 'Cancel', command = root.destroy)
        cn.pack(side='left')
        mainloop()

Screenshot:

tkValidatingEntry2.png

PythonPowered