I require a multi-line Text field with validation. It should, at
least, bounce graphic characters outside a small range. After much
messing with the options I have settled on this unhappy medium:
from Tkinter import *
def valid(vent):
if vent.keysym_num > 255: return
if vent.char not in "PERU":
text = vent.widget
text.event_generate('<Key-BackSpace>')
return
aText = Text()
aText.bind('<KeyRelease>', valid)
aText.pack()
mainloop()
Efforts to be more exact left the cursor in the wrong location,
or prevented copy-n-paste, or didn't work.
The problem with that code is it fails the chimp-test. If you bang
the keyboard you can insert characters faster than that recursive
I have liked to have intercepted the KeyPress event and removed
the character before it went in, but the 'event' object was one-way.
Does anyone have a better method?
--
Phlip
You would start with something like
def myfunc(evt):
k = evt.char
if k in "PERU": return
return "break"
aText = Text()
aText.bind("<KeyPress>", myfunc)
However, 'myfunc' will be executed even when the key is one such as
<Tab>, <Home>, or another key to be treated specially. For each such
key, you need a binding of the form
aText.bind("<Tab>", "# nothing")
as well as bindings to ignore modified keys
aText.bind("<Shift-Key>", "# nothing")
If you use an Entry instead of a Text, you can use textvariable= to link
the value in the entry to some Python instance. I'm not familiar with
doing this in Python, but the code might look something like this:
import Tkinter, re
class MyVariable(Tkinter.StringVar):
def __init__(self, master=None):
Tkinter.StringVar.__init__(self, master)
self.value = ""
self.trace = self.trace_variable("w", self._validate)
def __del__(self):
self.trace_vdelete("w", self.trace)
def _validate(self, name1, name2, op):
self.validate(self.get(), self.value)
self.value = self.get()
def validate(self, new_value, old_value):
self.set(new_value)
class PERUVariable(MyVariable):
def validate(self, new_value, old_value):
if re.match("^[PERU]*$", new_value):
self.set(new_value)
else:
self.set(old_value)
app = Tkinter.Tk()
aEntry = Tkinter.Entry(textvariable=PERUVariable(app))
aEntry.pack()
app.mainloop()
Jeff
> By returning the string "break" from a binding, you can stop further
Thank you thank you.
> processing of events, as described in the Tk "bind" manpage.
OOooh!!, an RTFM before the first period! I gotta lay off that crack pipe,
huh?
> If you use an Entry instead of a Text, you can use textvariable= to link
Thanks, but the multi-line requirement takes precedence.
Only-in-it-for-the-laudered-cash'ly y'rs
--
Phlip
the "Instance and Class Bindings" section on this page:
http://www.pythonware.com/library/tkinter/introduction/events-and-bindings.htm
discusses a similar case.
the easiest solution is to return the string "break" from the
event handler. (this prevents Tkinter from propagating the
event back to the standard handler).
</F>
<!-- (the eff-bot guide to) the python standard library:
http://www.pythonware.com/people/fredrik/librarybook.htm
-->