简体   繁体   中英

Tkinter Format Text on Entry

Formatting Text into a Time Format as the user Types

I'm trying to format text into the standard time format of 00:00:00 in a Tk.Entry textbox, as the user types in the numbers.

I understand that Tkinter is not the easiest, nor best optimized framework to format text while the user types, but I've managed to get this far:

from Tkinter import *

class Application(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()
        self.createWidgets()


    def createWidgets(self):
        sv = StringVar()
        sv.trace("w", lambda name, index, mode, sv=sv: self.entryUpdateEndHour(sv))
        endHourEntry = Entry(self, textvariable=sv)
        endHourEntry.pack()

    def entryUpdateEndHour(self, sv):
        global x

        x = sv.get()[0:2] + ':'
        y = x + sv.get()[3:5] + ':'
        z = y + sv.get()[6:8]

        sv.set(z)


root = Tk() 
app = Application(master=root) 
app.mainloop()

This prints out exactly what I want ( 12:45:67 ), but the live formatting is bad. For example, in typing two numbers I get 12::: in the textbox, and it skips every 3rd number I type in, since it replaces it with a : .

I would be very grateful if someone has any work arounds or solutions to this answer. Thanks in advance.

Here's my solution:

from Tkinter import *

class Application(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

    def createWidgets(self):
        sv = StringVar()
        endHourEntry = Entry(self, textvariable=sv)
        sv.trace("w", lambda name, index, mode, sv=sv: 
                             entryUpdateEndHour(endHourEntry))
        endHourEntry.pack()

def entryUpdateEndHour(entry):
    text = entry.get()
    if len(text) in (2,5):
        entry.insert(END,':')
        entry.icursor(len(text)+1)
    elif len(text) not in (3,6):
        if not text[-1].isdigit():
            entry.delete(0,END)
            entry.insert(0,text[:-1])
    if len(text) > 8:
        entry.delete(0,END)
        entry.insert(0,text[:8])


root = Tk() 
app = Application(master=root) 
app.mainloop()

For me, it's easier to work with the entry widget and not work with the StringVar directly. The only reason to include the stringvar at all is to get the tracing behavior so that the callback is called properly. Another option would be to do something with the vcmd option to the Entry constructor, but I can't seem to make that update the entry ... Only validate the contents.

from Tkinter import *

class Application(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()
        self.createWidgets()


    def createWidgets(self):
        sv = StringVar()
        sv.trace("w", lambda name, index, mode, sv=sv: self.entryUpdateEndHour(sv))
        self.endHourEntry = Entry(self, textvariable=sv)
        self.endHourEntry.pack()
        print [x for x in dir(self.endHourEntry) if 'set' in x]

    def entryUpdateEndHour(self, sv):
        digits = filter(str.isdigit, sv.get())
        sv.set('{}:{}:{}'.format(digits[:2], digits[2:4], digits[4:]))
        self.endHourEntry.icursor(END)


root = Tk() 
app = Application(master=root) 
app.mainloop()

Issue: cursor always go to end. I have no good idea about it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM