Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tkinter - Entry box - formatted for date

I would like to have an entry box for typing in dates so that the user can only type it one way.

The entry box before typing would look like this (without the underscores) __/__/____, and the /'s are not deleted when the user types the date.

Thanks

like image 761
Phil J Fry Avatar asked Dec 08 '22 19:12

Phil J Fry


2 Answers

Thanks to @Bryan Oakley's major hint, I have come up with this working code.

(Update: threw a few years of programming experience and some recent readers' sharp eyes at improving the code.)

from __future__ import print_function

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk


class DateEntry(tk.Frame):
    def __init__(self, master, frame_look={}, **look):
        args = dict(relief=tk.SUNKEN, border=1)
        args.update(frame_look)
        tk.Frame.__init__(self, master, **args)

        args = {'relief': tk.FLAT}
        args.update(look)

        self.entry_1 = tk.Entry(self, width=2, **args)
        self.label_1 = tk.Label(self, text='/', **args)
        self.entry_2 = tk.Entry(self, width=2, **args)
        self.label_2 = tk.Label(self, text='/', **args)
        self.entry_3 = tk.Entry(self, width=4, **args)

        self.entry_1.pack(side=tk.LEFT)
        self.label_1.pack(side=tk.LEFT)
        self.entry_2.pack(side=tk.LEFT)
        self.label_2.pack(side=tk.LEFT)
        self.entry_3.pack(side=tk.LEFT)

        self.entries = [self.entry_1, self.entry_2, self.entry_3]

        self.entry_1.bind('<KeyRelease>', lambda e: self._check(0, 2))
        self.entry_2.bind('<KeyRelease>', lambda e: self._check(1, 2))
        self.entry_3.bind('<KeyRelease>', lambda e: self._check(2, 4))

    def _backspace(self, entry):
        cont = entry.get()
        entry.delete(0, tk.END)
        entry.insert(0, cont[:-1])

    def _check(self, index, size):
        entry = self.entries[index]
        next_index = index + 1
        next_entry = self.entries[next_index] if next_index < len(self.entries) else None
        data = entry.get()

        if len(data) > size or not data.isdigit():
            self._backspace(entry)
        if len(data) >= size and next_entry:
            next_entry.focus()

    def get(self):
        return [e.get() for e in self.entries]


if __name__ == '__main__':        
    win = tk.Tk()
    win.title('DateEntry demo')

    dentry = DateEntry(win, font=('Helvetica', 40, tk.NORMAL), border=0)
    dentry.pack()

    win.bind('<Return>', lambda e: print(dentry.get()))
    win.mainloop()
like image 76
pydsigner Avatar answered Dec 12 '22 11:12

pydsigner


I have discovered a very simple solution. I hope someone can find it useful.

self.entry1=tk.Entry(self)
self.entry1.insert(END, "    /    /        ")
self.entry1.config(fg="grey")

def datemask(self, event):
if len(self.entry1.get()) is 2:
    self.entry1.insert(END,"/")

elif len(self.entry1.get()) is 5:
    self.entry1.insert(END,"/")

elif len(self.entry1.get()) is 11:
    self.entry1.delete(10, END)

Bind the entry widget

self.entry1.bind('<KeyRelease>', self.datemask)
like image 37
Waheed Ahmad Avatar answered Dec 12 '22 13:12

Waheed Ahmad