Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ScrolledText (over Tkinter.Text) validation

3 views
Skip to first unread message

Phlip

unread,
May 20, 2002, 1:39:00 PM5/20/02
to
Hypo Nt:

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

Jeff Epler

unread,
May 20, 2002, 2:02:16 PM5/20/02
to
By returning the string "break" from a binding, you can stop further
processing of events, as described in the Tk "bind" manpage.

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


Phlip

unread,
May 20, 2002, 2:43:54 PM5/20/02
to
"Jeff Epler" wrote:

> 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


Fredrik Lundh

unread,
May 20, 2002, 2:45:39 PM5/20/02
to
"Phlip" wrote:
>
> 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?

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
-->


0 new messages