Credit: Alex Martelli
You want to validate the contents of a line-entry widget on the fly while the user is entering data and give unobtrusive feedback about whether the current contents are valid, incomplete, or invalid.
Changing the widget’s background color to different shades is an excellent way to provide unobtrusive feedback during data entry. As usual, it’s best to package the solution as a reusable widget:
from qt import * class ValidatingLineEdit(QLineEdit): colors = Qt.red, Qt.yellow, Qt.green def _ _init_ _(self, validate, parent=None, name=None): QLineEdit._ _init_ _(self, parent, name) self.validate = validate self.connect(self, SIGNAL("textChanged(const QString &)"), self.changed) self.color = None self.changed('') def changed(self, newText): colorIndex = self.validate(unicode(newText)) if colorIndex is None: return color = self.colors[colorIndex].light(196) if color != self.color: self.setPaletteBackgroundColor(color) self.color = color
The function passed as the validate
argument must
accept a Unicode string and return either None
,
meaning no color change, or an index into the
widget’s colors
attribute. By
default, 0
indicates red (an incorrect entry),
1
indicates yellow (an incomplete entry), and
2
indicates green (an entry that is already
acceptable).
When the user is entering data in a line-entry field, it can be helpful to validate the field’s contents on the fly, at every change, and give unobtrusive feedback about whether the current content is valid, incomplete, or invalid. One way to do this is by setting the field’s background color accordingly (using light pastel shades, not strong contrast colors, so the feedback is unobtrusive).
Qt has a reputation for being cranky about color control, but Qt 3
now supplies the
setPaletteBackgroundColor
method on all widgets, which is effective for our specific purpose.
This recipe packages a
LineEdit
widget with the minimal amount of
infrastructure to ensure that the background color is changed
appropriately, based on a validation function that you pass when you
instantiate the widget.
Here is a simple validation function, suitable for instantiating a
ValidatingLineEdit
widget. As an example
criterion, this function assumes that a valid entry is one containing
4, 5, or 6 digits, and no character that is not a digit:
def validate(text): if not text: return 1 # empty -> "incomplete" if not text.isdigit( ): return 0 # nondigits -> "invalid" if len(text) < 4: return 1 # too short -> "incomplete" if len(text) > 6: return 0 # too long -> "invalid" return 2 # otherwise -> "acceptable"
Note that you can also customize the widget’s
colors
attribute by assigning to it a tuple of
QColor
instances of your choice at any time. The
validation function must always return either
None
, meaning no color change, or a valid index
into the widget’s current colors
attribute.
If content-validation takes a long time, you should delay validating the field and wait until the user is done with it. Often, a good time for relatively lengthy validation is when the entry widget loses focus, although it may be simplest (but maybe not as effective, ergonomically) to validate all fields only when the user clicks an OK button (the latter strategy is surely preferable when complex validation criteria depend on the contents of several widgets).
This widget’s architecture is simpler, and a bit
less flexible, than the usual, recommended Qt approach. To be
Qt-canonical, you should emit signals and expose slots, leaving it up
to containers and applications to connect
them
appropriately. This is an excellent approach, and a flexible one, but
simplicity also has its appeal. You should be aware of the vast
potential of the signals/slots approach, but—unless
you’re writing widgets for mass
distribution—you can wait to architect this approach into a
specific customized widget until you need it in your application.
Information about Qt is available at http://www.trolltech.com; PyQt is available and described at http://www.riverbankcomputing.co.uk/pyqt/index.php.
Get Python Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.