How do i set a limit in an Entry widget

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • bkunjitam
    New Member
    • Nov 2006
    • 17

    How do i set a limit in an Entry widget

    Hi,

    I have an Entry widget where in i can enter string.

    Clarifications needed:

    1. The user should not be able to exceed 15 characters at the max in the Entry widget. How do i set the limit for the same.

    2. The user should not be able to enter "SPACE". Is there any such provisions for the same?

    Can the same be done in Text widget?
  • bartonc
    Recognized Expert Expert
    • Sep 2006
    • 6478

    #2
    I wrote these classes (sub classes of tkinter.entry). The do all kinds of validation. You can use these a base for your own subclasses.
    Code:
    from Tkinter import *
    from dbtools import *
    from datetime import date, time
    from calendar import monthrange
    
    ### I tried using Tk's validatecommand callback, but it works badly.
    ### Access and choice of event bindings is much better this way.
    ### The creation of the set() method make these widgets looks like Variables.
    
    class ValidEntry(Entry):
        """Validate the value of an entry widget; Use escape to go back to
        previous value.
        A callback routine which expects the event
        can optionally be notified of changes to the entry. Set next to
        a widget instance that whould get the focus next on <Return>."""
        def __init__(self, master=None, callback=None, minvalue=None, maxvalue=None,
                     cnf={}, **kw):
            try:
                self.next = kw.pop('next')
            except KeyError:
                self.next = None
            try:
                self.receiver = kw.pop('receiver')
            except KeyError:
                self.receiver = None
            try:
                self.nullProc = kw.pop('nullProc')
            except KeyError:
                self.nullProc = None
            Entry.__init__(self, master, cnf, **kw)
    
            self.callback = callback
            self.minvalue = minvalue
            self.maxvalue = maxvalue
            self.oldvalue = ''
    
            self.bind('<Tab>', self.CheckValue)
            self.bind('<Return>', self.CheckValue)
            self.bind('<FocusOut>', self.CheckValue)    # For clicks outside this widget
            self.bind('<FocusIn>', self.ReFocus)
            self.bind('<Escape>', self.UndoValue)
    
        def set(self, value):
            self.delete(0,END)
            self.insert(0, str(value))
            self.oldvalue = str(value)
    
        def replace(self, value):
    ##        print 'replacing %s with %s' %(repr(self.oldvalue), repr(value))
            if self.oldvalue:
                self.oldvalue = ''
            self.delete(0,END)
            self.insert(0, str(value))
    
        def clear(self):
            self.set('')
    
        def convert(self, value=None):
            """Override this method to return an alternate format (or type)"""
            if value is None:
                value = self.get()
            return value
    
        def CheckValue(self, event=None):
            """If the current value is equal to oldvalue, there's nothing to
               check.  Else, validate() may change the the user-entered value,
               so re-get() and store in oldvalue. Callbacks happen for new valid
               values. Events are generated for old values and new valid values."""
            if event is None:
                event = Event()
                event.widget = self
                event.type = '35'
    ##        print 'checking %s' %event.widget
            value = self.get()
            isvalid = True
            if value != self.oldvalue:
                if value:
                    isvalid = self.Validate(value)
                if isvalid:
                    if type(isvalid) == bool:
                        newvalue = self.get()
                        self.oldvalue = newvalue
                        self.select_clear()
                        self.icursor(END)
                        if self.callback is not None:
    ##                        print 'calling back'
                            self.callback(event)
                    else: self.Invalid(isvalid[0], isvalid[1])
                else:
                    self.Invalid()
            else:
                self.SendEvent(event)
            if isvalid:
                if event.type == '2' or event.type == '35':
                    if self.next is not None:
                        self.next.focus_set()
    
        def Invalid(self, index1=0, index2=END):
            self.bell()
            self.focus_set()
            self.select_range(index1, index2)
            self.icursor(index1)
    
        def Validate(self, value):
            """An override of this method may re-format the string
            and then store it by calling self.replace(newvalue).
            Call this method from inside a try block that catches the
            ValueError exception for min/max checking after converting
            the string to a hashable type"""
    
            minvalue = self.minvalue
            if minvalue is not None and value < minvalue:
                raise ValueError
            maxvalue = self.maxvalue
            if maxvalue is not None and value > maxvalue:
                raise ValueError
            return True
    
        def ReFocus(self, event=None):
            self.select_range(0, END)
            self.icursor(END)
    
        def UndoValue(self, event=None):
            """Pass the <Escape> to the receiver."""
            self.set(self.oldvalue)
            self.ReFocus()
            try:
                self.receiver.event_generate("<<Entry_Escape>>")
            except AttributeError: pass
    
        def ReturnEvent(self):
            """Generate a <Return> event in this widget."""
            event = Event()
            event.widget = self
            event.type = '2'
            self.icursor(END)
            self.CheckValue(event)
    
        def SendEvent(self, event):
            """Pass the <Tab>, <Return>, <FocusOut> up the chain when
               the value didn't change."""
            try:
                self.nullProc(event)
            except TypeError: pass
    
        def SetNextWidget(self, nextWidget):
            self.next = nextWidget
    
        def GetNextWidget(self):
            return self.next
    
        def SetRecWidget(self, receiver):
            self.receiver = receiver
    
        def SetNullProc(self, nullProc):
            self.nullProc = nullProc
    
        def SetCallback(self, callback):
            self.callback = callback
    
        def Close(self):
            self.ReturnEvent()
    
    class IntegerEntry(ValidEntry):
        def Validate(self, value):
            try:
                a = int(value)
                ValidEntry.Validate(self, a)
                return True
            except ValueError:
                return False
    
        def convert(self, value=None):
            if value is None:
                value = self.get()
            try:
                value = int(value)
            except ValueError:
                pass
            return value
    
    class FloatEntry(ValidEntry):
        def Validate(self, value):
            try:
                a = float(value)
                ValidEntry.Validate(self, a)
                return True
            except ValueError:
                return False
    
        def convert(self, value=None):
            if value is None:
                value = self.get()
            try:
                value = float(value)
            except ValueError:
                pass
            return value
    
    class HexEntry(ValidEntry):
        def Validate(self, value):
            try:
                a = int(value, 16)
                ValidEntry.Validate(self, a)
                self.replace(value.upper())
                return True
            except ValueError:
                return False
    
    class StringEntry(ValidEntry):
        """Disable minvalue and maxvalue, allow all text."""
        def Validate(self, value):
            return True
    
    class StateEntry(ValidEntry):
        def Validate(self, value):
            if len(value) > 2 or not value.isalpha():
                return False
            self.replace(value.upper())
            return True
    
    class NameEntry(ValidEntry):
        def Validate(self, value):
            l = value.split()
            value = ' '.join(value.capitalize() for value in l)
            self.replace(value)
            return True
    
    class PhoneEntry(ValidEntry):
        def Validate(self, value):
            for char in set(' -()').intersection(value):
                l = value.split(char)
                value = ''.join(l)
            i = len(value)
            if i >= 7:
                if i == 7 and int(value[0]) > 1:
                    self.replace('%s-%s' %(value[:3], value[3:]))
                    return True
                if i == 8 and value[0] == '1':
                    self.replace('1-%s-%s' %(value[1:4], value[4:]))
                    return True
                if i == 10 and int(value[0]) > 1:
                    self.replace('(%s) %s-%s' %(value[:3], value[3:6], value[6:]))
                    return True
                if i == 11 and value[0] == '1':
                    self.replace('1-(%s) %s-%s' %(value[1:4], value[4:7], value[7:]))
                    return True
            return False
    
    
    
    if __name__ == '__main__':
        root = Tk(className='widget test window')
        top = Frame()
        top.pack()
    
        def cb(event):
            print 'Callback called by event type %s' %(event.type)
    
        de = DateEntry(top, width=11, callback=cb)
        pe = PhoneEntry(top, width=15, callback=cb)
        ne = TimeEntry(top, callback=cb)
    
        de.next = pe
        pe.next = ne
        ne.next = de
    
        de.pack()
        pe.pack()
        ne.pack()
        de.setdate('')
        root.mainloop()

    Comment

    Working...