data entry validation with Tkinter
Russell E. Owen
owen at astroNOJNK.washington.edu.invalid
Tue Aug 7 19:26:29 EDT 2001
In article <mailman.997189391.19119.python-list at python.org>, Ken Guest
<kwg at renre-europe.com> wrote:
>On 07 Aug 2001 13:16:36 +0100, Martin Franklin wrote:
>> Ken,
>>
>> Take a look at the Pmw (Python Mega Widgets)
>> they've got an EntryField with validation plus some
>> built in validators (including dates, numbers, etc)
>> I use it for validating filenames.
>
>hi Martin,
>thanks for that, but I'm fairly much committed to using tkinter.
>Can they both (tkinter and pmw) coexist within the same application?
>That might make things more likely to be reconsidered
>(as we're migrating a tcl+tk app over to python and really don't
>want to change too much of it too quickly).
Pmw is basically a wrapper for Tkinter, so they work together very well.
I found the Pmw widgets did not do what I wanted, so I rolled my own
using Tk variables to fire a checking function whenever the user types a
character in the entry widget. A copy of one example is appended. I also
have integer and sexagesimal (e.g. dd:mm:ss.s) entry widgets (which
subclass FloatEntry), in case those are of interest.
Notes:
- var.trace_variable is the heart of the checker. var is a Tk variable
associated with the entry widget. trace_variable sets a callback
function that is called whenever the variable is changed.
- ROStringUtil.strToFloat is similar to Float but is more liberal in
what it accepts, for instance "" is 0.0 and None is NaN and is displayed
as blank. Full source available on request.
Any fixes or suggestions for improvement would be most welcome.
Sorry for the anti-spam return address.
-- Russell
class FloatEntry (Entry):
"""A widget for entering floating point numbers with validity and
range checking.
Warning: cannot handle exponential notation, yet; as soon as you
type an e
the string can no longer be parsed as a float. This could certainly
be fixed
but it might be best to make a separate widget for the purpose.
"""
def __init__ (self, master, minValue, maxValue, defValue=None,
var=None, **kargs):
"""Create a FloatEntry widget.
Inputs:
master master Tk widget -- typically a frame or window
minValue minimum acceptable value; a number is required
maxValue maximum acceptable value; a number is required
defValue default value; if supplied then it must be a
valid number
var a StringVar to use as the widget's Tk variable
**kargs keyword arguments to configure the widget;
the default width is 8
text and textvariable are silently ignored (use var
instead of textvariable)
"""
if var:
self.var = var
else:
self.var = StringVar()
self.minValue = minValue
self.maxValue = maxValue
self.defValue = defValue
if not kargs:
kargs = {}
kargs.setdefault("width", 8)
kargs.setdefault("justify", RIGHT)
if kargs.has_key("text"):
del(kargs["text"])
kargs["textvariable"] = self.var # overrides user attempt to set
Entry.__init__(self, master, **kargs)
self.oldVal = self.var.get()
self.var.trace_variable("w", self._checkVar)
# set default -- do after binding _checkVar, so default is
checked
self.restoreDefault()
self.bind("<FocusOut>", self._focusOut)
def clear(self):
self.var.set("")
def getDefault(self):
return self.defValue
def getFloat(self):
"""Return the floating point value of the field"""
return ROStringUtil.strToFloat(self.var.get())
def getString(self):
return self.var.get()
def getVar(self):
return self.var
def restoreDefault(self):
if self.defValue:
# set default value and check it
self.setFloat(self.defValue)
else:
# clear the field
self.var.set("")
def set(self, stringValue):
"""Set the field from a string; reject bad data.
error conditions:
raises ValueError if the string cannot be parsed
"""
self.var.set(stringValue)
def setFloat(self, floatValue):
"""Set the field based on a floating point value"""
self.var.set(floatValue)
def setRange(self, minValue, maxValue):
self.minValue = minValue
self.maxValue = maxValue
def _checkVar(self, *args, **kargs):
try:
newVal = self.var.get()
# blank is always acceptable
if not newVal:
return
# check format (by convering to float) and that the new
value is in range
floatVal = self.getFloat()
if floatVal < self.minValue or floatVal > self.maxValue:
raise ValueError, "value %s out of range [%g,%g]" % \
(newVal, self.minValue, self.maxValue)
self.oldVal = newVal
except StandardError, e:
print e
self.var.set(self.oldVal)
self.bell()
def _focusOut(self, evt=None):
"""If blank, insert default value"""
currVal = self.var.get()
if not currVal:
self.restoreDefault()
More information about the Python-list
mailing list