I need a little help with Tkinter Entry widget

Phil Schmidt phil_nospam_schmidt at yahoo.com
Fri Sep 5 16:35:52 EDT 2003


I'm trying to make a custom entry widget, as in the code that follows.
There are two problems I'm trying to fix:

1) I would like the widget to behave as myEntry.Escape() does now,
except that it happens on loss of focus, not when pressing Esc.

2) TABbing between multiple entry fields does undesired things with
the selection, and with cursor placement.

Can anyone offer any suggestions for how to fix this? I'm attemting to
replicate, more or less, the behavior one would get with, for example,
MS Excel, in navigating and entering data in an array of entry fields.

Also, I'd appreciate any critique of my overall technique,
particularly in how I've implemented the "undo" behavior - it works,
but doesn't seem particularly clean.

Thanks!

------------------------------------------------------

from Tkinter import *

class history:
    """this is a mixin for my custom widgets,
    providing for "infinite" undo."""
    LOG = []
    COUNT = {}
    def log(self):
        history.LOG.append((self, self.value))
        history.COUNT.setdefault(id(self), 0)
        history.COUNT[id(self)] += 1
    def undo(self):
        try:
            s, v = history.LOG.pop()
            if history.COUNT[id(s)]:
                s.value = v
                history.COUNT[id(s)] -= 1
                if not history.COUNT[id(s)]:
                    del history.COUNT[id(s)]
                s.Show()
        except IndexError:
            pass

class myEntry(Entry, history):
    """
    This works pretty well, with one exception: I would like the
    widget to behave as Escape() does now, except that it happens
    on loss of focus, not when pressing Esc.

    Also, TABbing between entry fields causes the text in the next
    widget to be selected, with the cursor at the end of the text.
    When keys are pressed, the text is appended to the selected
    text, rather than replacing the selection as would be expected.
    """
    def __init__(self, master=None, state=NORMAL, **config):
        Entry.__init__(self, master, **config)
        if master == None:
            self.pack()
        self.insert(INSERT, str(self))
        self.bind('<Return>', self.Return)
        self.bind('<Escape>', self.Escape)
        self.bind('<Key>', self.Key)
        self.bind('<Control-z>', self.ctrl_z)
        self.mode = 'display'
        if state == DISABLED:
            self.config(state=DISABLED)
    def Show(self):
        self.delete(0, END)
        self.insert(INSERT, str(self))
        self.mode = 'display'
        try:
            history.COUNT[id(self)]     # fails if no history
(changes)
            self.config(bg='pink', fg='black')
        except:
            self.config(bg='white', fg='black')
    def Key(self, event):
        try:
            x = ord(event.char)     # fails if not an ASCII key
            if event.keysym == 'Tab':
                self.Return(None)
            elif self.mode == 'display':
                self.config(bg='red', fg='white')
                self.mode = 'entry'
                E, I = self.index(END), self.index(INSERT)
                self.delete(0, END)
                self.insert(INSERT, self.STR())
                i = self.index(END)
                self.icursor(i - (E - I))
        except:
            pass
    def Return(self, event):
        if self.focus_get():
            self.Validate(self.get())
            self.Show()
    def Escape(self, event):
        self.Show()
    def ctrl_z(self, event):
        self.undo()
    def Validate(self, value):
        pass

class gui_int(myEntry):
    def __init__(self, value=0, master=None, **config):
        self.value = 0
        myEntry.__init__(self, master, **config)
    def Validate(self, value):
        try:
            v = int(value)
            if v != self.value:
                self.log()
                self.value = v
        except:
            pass
    def __str__(self):
        return 'INT: ' + str(self.value)
    def STR(self):
        return str(self.value)

x=gui_int(value=22.34, font='Courier 12', state=DISABLED, width=11,
justify=RIGHT)
y=gui_int(font='Courier 12', width=11, justify=RIGHT)
z=gui_int(value=10.99, font='Courier 12', width=11, justify=RIGHT)




More information about the Python-list mailing list