Updated 2011-07-29 21:28:28 by dkf

Beginning with Tk 8.3, the entry widget has built-in hooks for validating the contents of an entry. By adding a little code to the entry widget, you can check the entered data on the fly. Be sure to read the new entry manual page [1] for a full description and cautions about mixing validation code with text variables.

Examples of entry widget validation include, but are not limited to:

Here are a few examples of entry validation, in the form of a widget demo, courtesy of Jeffrey Hobbs with a few additions by yours truly (RWT). Feel free to add more validation examples that you find useful.

Also, be aware that Wcb is a script library that you may find useful for these sorts of things.

It is worth noting that some of the regular expressions look a little odd. The Real Number expression, for example, will allow -9.9.e-9 if you are checking any string with ''regexp' (which is why I've replaced it with a simpler validator - DKF.) But you cannot progressively build up to that string. ("-9.9." will fail!) The validation command must be defined in the context of the mode defined by the -validate switch.

DKF adds:

If you have some complex string that you are needing to enter, then you might prefer to perform validation on some criterion other than a key press - it is easy to imagine that the requirement that an entry have a minimum of 4 characters in it will be violated when you are entering the first of them - and it is even possible that you will want several different kinds of validation, depending on whether it is triggered by a key press (when you check to see if the key is a reasonable thing at that point) or, for example, a focus-out (when you check to see if the contents really is valid overall.)

A deeper question is how you report a validation failure to the user. Popping up a dialog box to report the failure is probably not a good idea, especially if the user hasn't finished with the form just yet! From what I've seen in practise and read in the likes of About Face, I'd say that the best technique is to be as lenient as possible with typing during the main part of the data entry, indicating failed validations using subtle hints (e.g. by changing the colour of the associated label from the usual sedate black on grey to red on grey) and only when the whole form is accepted by the user should you perform any more stringent validation, and failures should be reported by sounding the bell (never neglect the power of aural feedback) and moving the focus to the first of the fields whose validations failed (though all should be marked.) Reserve dialog boxes for when a particularly complex and rarely-failed validation doesn't work, since dialogs are really disruptive to people's workflows and have only limited pedagogic value (these particular dialogs are also ideal candidates for being switched off individually by users.)

[ AK -- Regarding aural feedback ... I personally consider it to intrusive. And people will not like it if their problems are announced to the world around them. Changing background colors are seen only by me. The beep is heard all over. ]

LV And using colors as indicators will of course be frustrating for someone who is blind (either legally or just color blind...).

When you have fields that are co-validated, you must always validate them as a group, even for trivial changes (since a change to one might make a previously invalid field become valid, or vice versa.)

If you've taken the time to add an online-help system to your application, then that help should describe what sorts of validations are being done. Like that, anyone who forgets how a particular validation is done (from their perspective obviously; only a programmer would like to see the regexp being used!) can remind themselves with the press of a key or the touch of a button.

KBK observes further:

At one point, I had a customer who wanted an entry field that would validate a time of day (HH:MM:SS); actually, since the application was for video processing, the time also included a frame count within the second, but that's not really relevant to the discussion. The customer found "validate-on-focus-out" to be unacceptable: he wanted the field NEVER to have invalid content. What the customer (and, surprisingly, the users) actually liked was to put a sample time in the field, and set up the keyboard bindings to function in overtype mode. The key bindings got to be a bit complicated, since they were dependent on the location of the entry cursor. I was going to post the code at Time entry that never contains invalid data, but it turns out to be too large for my web browser.

    label .l1 -text "Integer:"
    entry .e1 -validate key -vcmd {string is int %P}

    label .l2 -text "Integer && 7 char limit:"
    entry .e2 -validate key \
            -vcmd {expr {[string is int %P] && [string length %P]<8}}

    label .l3 -text "Integer with leading +/-:"
    entry .e3 -validate key \
            -vcmd {expr {[string match {[-+]} %P] || [string is int %P]}}

    label .l4 -text "Integer forbidding leading zero:"
    entry .e4 -validate key \
            -vcmd {expr {[string is int %P] && ![string match "0*" %P]}}

    label .l5 -text "Real Number:"
    entry .e5 -validate key -vcmd {string is double %P}

    label .l6 -text "Alpha:"
    entry .e6 -validate key -vcmd {string is alpha %P}

    label .l7 -text "Hexadecimal:"
    entry .e7 -validate key -vcmd {string is xdigit %P}

    label .l8 -text "8 char limit:"
    entry .e8 -validate key -vcmd {expr {[string len %P] <= 8}}

    grid .l0 -columnspan 2 -sticky w
    grid .l1 .e1
    grid .l2 .e2
    grid .l3 .e3
    grid .l4 .e4
    grid .l5 .e5
    grid .l6 .e6
    grid .l7 .e7
    grid .l8 .e8
    grid configure .l1 .l2 .l3 .l4 .l5 .l6 .l7 .l8 -sticky e
    grid configure .e1 .e2 .e3 .e4 .e5 .e6 .e7 .e8 -sticky ew
    grid columnconfigure . 1 -weight 1

Question edit

This might be revealed when I get into experimenting with entry validation, but the man pages do not address the question. If validation is set to run on focusout, and the validatecommand returns 0, is focus retained by the entry widget automatically? Or if not, is there a good (and/or safe) way for the invalidcommand to set focus back to the entry widget?

I'm thinking of cases where the application will not allow focus to leave an entry that has invalid data still in it. Perhaps this is considered too rude behavior.

David S. Cargo (dcargo@marix.com)

Matthias Hoffmann: Just noticed, with the latest tclkit-win32.exe, that the entry validation just worked one time. After the first test, the validation turns inactive. Example:
 proc checkRecv {P} {
     if {[string length $P] > 40} {
        tk_messageBox -title Fehler! \
                      -message "Das Eingabefeld darf maximal 40 Zeichen enthalten!" \
                      -icon error
        set rc 0
     } else {
        if {[string is print $P]} {
           set rc 1
        } else {
           tk_messageBox -title Fehler! \
                         -message "Das Eingabefeld darf keine Steuerzeichen enthalten!" \
                         -icon error
           set rc 0
     # Bugfix; without that, validation is switched off after the first run .... (????)
     after idle {.edit.eRecv config -validate all -vcmd {checkRecv %P}}
     return $rc

See also edit