Tkinter Text widget reading input (how to do overwrite mode?)

Jeff Epler jepler at unpythonic.net
Mon Apr 29 14:20:06 EDT 2002


On Mon, Apr 29, 2002 at 10:00:39AM -0500, Jeff Epler wrote:
> I have implemented an 'overwrite mode' in the Text widget in tcl.
> Conversion to Python is left as an exercise to the reader.

Okay, I can't stand an unfinished exercise.  In my "testing", I decided
that it could stand to be a little smarter, in particular when the
insertion point is at the end of a line and I'm in overwrite mode, I don't
expect the newline to be removed to make room for the new character.

Since arbitrary new attributes can be hung on a Python class, there's no
fooling around with a fake tag on the text widget .. yay Python!

Things still behave slightly oddly when the widget contains the
selection.  If the overlined characters are selected and | shows the
insertion point, here's what happens when you overwrite "x":
        ____
    abc|defghijk
becomes
    abcx|ijk
This suggests that a test should be made for whether "nextchar" lies
inside the selection -- if so, the step inside Text's KeyPress binding
which deletes the selected text will delete it for us.

# --- overwritetext.py
import Tkinter

def comparable_index(index):
    return map(int, index.split("."))

class OverwriteText(Tkinter.Text):
    def __init__(self, *args, **kw):
	Tkinter.Text.__init__(self, *args, **kw)
	tags = list(self.bindtags())
	idx = tags.index("Text")
	tags[idx:idx] = ["OverwriteText"]
	self.bindtags(tuple(tags))
	self.is_overwrite = 0

	if not self.bind_class("OverwriteText"):
	    self._init_bindings()

    def _init_bindings(self):
	self.bind_class("OverwriteText", "<KeyPress>",
	    lambda evt: OverwriteText.KeyPress(evt.widget, evt))
	self.bind_class("OverwriteText", "<Insert>",
	    lambda evt: OverwriteText.Insert(evt.widget, evt))

    def toggle_overwrite(self):
	self.is_overwrite = not self.is_overwrite

    def KeyPress(self, evt):
	if self.is_overwrite:
	    eol = self.index("insert lineend")
	    nextchar = self.index("insert + %dc" % len(evt.char))
	    eol_num = comparable_index(eol)
	    nextchar_num = comparable_index(nextchar)
	    if eol_num < nextchar_num:
		index = eol
	    else:
		index = nextchar
	    self.delete("insert", index)

    def Insert(self, evt):
	self.toggle_overwrite()
	return "break" # Don't insert clipboard text

def _test():
    import sys
    t = OverwriteText()
    t.pack()
    t.insert(0.0, open(sys.argv[0]).read())
    t.mainloop()

if __name__ == '__main__': _test()





More information about the Python-list mailing list