Tkinter Формат текста на входе

Форматирование текста в формате времени по типу пользователя

Я пытаюсь отформатировать текст в стандартный формат времени 00:00:00 в текстовом поле Tk.Entry, когда пользователь вводит цифры.

Я понимаю, что Tkinter - не самая простая и не лучшая оптимизированная среда для форматирования текста, когда пользователь печатает, но мне удалось продвинуться так далеко:

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()

Это распечатывает именно то, что я хочу (12:45:67), но живое форматирование плохо. Например, при наборе двух чисел я получаю 12::: в текстовом поле, и он пропускает каждый третий номер, который я ввожу, так как он заменяет его на :,

Я был бы очень признателен, если у кого-нибудь есть обходные пути или решения для этого ответа. Заранее спасибо.

2 ответа

Решение

Вот мое решение:

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()

Для меня проще работать с виджетом ввода, а не напрямую с StringVar. Единственная причина, по которой вообще нужно включить stringvar, - получить поведение трассировки, чтобы обратный вызов вызывался правильно. Другим вариантом будет сделать что-то с vcmd опцию конструктора Entry, но я не могу сделать это обновить запись... Только проверить содержимое.

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()

Проблема: курсор всегда идет до конца. Я понятия не имею об этом.

Другие вопросы по тегам