[Tkinter-discuss] tkinter Entry validation: insert instead of replace

Doc Lans codelans at gmail.com
Sat Feb 23 00:35:24 CET 2013


I removed your focus bind and all Entries work fine for me. I cannot insert
something incorrect and cannot leave Entries blank.

import Tkinter

class IntEntry(Tkinter.Entry):
    def __init__(self, master=None, value=0, **kw):
        Tkinter.Entry.__init__(self, master, **kw)
        self._oldvalue = value
        self.insert('end', value)
        vcmd = (self.register(self._validate), '%s', '%P')
        self.configure(validate='all', vcmd=vcmd)
        self.bind('<FocusOut>', self._focus_out)

    def _focus_out(self, event):
        self.get()

    def _validate(self, old, new):
        if old != '':
            self._oldvalue = old
        if new == '':
            return True
        return new.isdigit()

    def get(self):
        value = Tkinter.Entry.get(self)
        if value == '':
            self.insert('end', self._oldvalue)
            value = self._oldvalue
        return int(value)

    def set(self, value):
        self.delete(0, 'end')
        self.insert('end', value)

def printer():
    for i in vals:
        print i.get(),
    print

root = Tkinter.Tk()
vals = []
for i in range(5):
    e = IntEntry(root, value=(i + 1) * 111)
    e.pack(side='top', padx=5, pady=5)
    vals.append(e)
Tkinter.Button(text='print all', command=printer).pack(side='top')
root.mainloop()

2013/2/23 Michael Lange <klappnase at web.de>

> On Fri, 22 Feb 2013 21:59:50 +0600
> Teodor the Thinker <doctorlans at gmail.com> wrote:
>
> > Thank you. It was so simple! I changed function return to
> > return P.isdigit() or (P == "")
> > and it seems work.
> >
> > But it allows empty string not only during editing. I want to make:
> > when i clear the Entry and switch to another GUI element Entry
> > rollbacks to last valid value.
> >
> > But obvious code to achieve this goal doesnt work:
> > if P == "" and V == 'focusout':
> >     return False
> > else:
> >     return (P.isdigit() or P == "")
> >
> > I found when "return False" is executed, *s* variable is empty. So i
> > need to rollback not for last but to *before last* value. Is there a
> > nice bultin Tkinter way to achieve that or i should declare some
> > variable with "before last value" by my own?
>
> There is no (or at least I don't know of) any built-in way to do this.
>
> One possible way to work around this is to store the old value and restore
> it if required, as in this example:
>
> ##############################################################
> import Tkinter
>
> class IntEntry(Tkinter.Entry):
>     def __init__(self, master=None, value=0, **kw):
>         Tkinter.Entry.__init__(self, master, **kw)
>         self._oldvalue = value
>         self.insert('end', value)
>         vcmd = (self.register(self._validate), '%s', '%P')
>         self.configure(validate='all', vcmd=vcmd)
>         self.bind('<FocusOut>', self._focus_out)
>
>     def _focus_out(self, event):
>         self.get()
>
>     def _validate(self, old, new):
>         if old != '':
>             self._oldvalue = old
>         if new == '':
>             return True
>         return new.isdigit()
>
>     def get(self):
>         value = Tkinter.Entry.get(self)
>         if value == '':
>             self.insert('end', self._oldvalue)
>             value = self._oldvalue
>         return int(value)
>
>     def set(self, value):
>         self.delete(0, 'end')
>         self.insert('end', value)
>
> root = Tkinter.Tk()
> e1 = IntEntry(root, value=111)
> e1.pack(side='top', padx=100, pady=20)
> e2 = IntEntry(root, value=222)
> e2.pack(side='bottom', padx=100, pady=20)
> def test(event):
>     print 'test'
> e2.bind('<FocusOut>', test)
> root.mainloop()
> ##############################################################
>
> This appears to work rather robust, it takes even care that get()
> will always return a decent value.
> However you see the weak point of this approach in the second Entry where
> a new binding to <FocusOut> events stops the validation from working
> properly.
> Using the "%V" substitution in the _validate() callback seems not to be
> exactly an alternative, because calling insert() from within the
> validation callback will again start validation and the results are hard
> to predict; sooner or later it may happen that Tk decides to turn off
> validation at all (at least I never managed to get such setups working).
>
> An alternative may (or may not ;) be to use the modified get() as above
> but to leave the empty Entries alone until some procedure is started by
> the user that calls get() which will automagically restore the last sane
> value (that's in fact what I did in one of my programs where I took the
> above example from).
>
> Regards
>
> Michael
>
> .-.. .. ...- .   .-.. --- -. --.   .- -. -..   .--. .-. --- ... .--. . .-.
>
> Another war ... must it always be so?  How many comrades have we lost
> in this way? ...  Obedience.  Duty.  Death, and more death ...
>                 -- Romulan Commander, "Balance of Terror", stardate 1709.2
> _______________________________________________
> Tkinter-discuss mailing list
> Tkinter-discuss at python.org
> http://mail.python.org/mailman/listinfo/tkinter-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tkinter-discuss/attachments/20130223/8828e807/attachment-0001.html>


More information about the Tkinter-discuss mailing list