В интерактивном режиме проверки записи содержимого виджета в tkinter
каков рекомендуемый метод для интерактивной проверки содержимого в tkinter Entry
виджет?
Я читал сообщения об использовании validate=True
и validatecommand=command
, и кажется, что эти функции ограничены тем, что они очищаются, если обновление виджета.
учитывая такое поведение, мы должны связать на KeyPress
,Cut
и Paste
события и мониторинг / обновление нашего Entry
значение виджета через эти события? (И другие связанные с этим события, которые я мог пропустить?)
или мы должны полностью забыть интерактивную проверку и проверять только на FocusOut
событий?
4 ответа:
использовать
Tkinter.StringVar
для отслеживания значения виджета ввода. Вы можете проверить значениеStringVar
установкаtrace
на нем.вот короткая рабочая программа, которая принимает только допустимые поплавки в виджете ввода.
from Tkinter import * root = Tk() sv = StringVar() def validate_float(var): new_value = var.get() try: new_value == '' or float(new_value) validate.old_value = new_value except: var.set(validate.old_value) validate.old_value = '' # trace wants a callback with nearly useless parameters, fixing with lambda. sv.trace('w', lambda nm, idx, mode, var=sv: validate_float(var)) ent = Entry(root, textvariable=sv) ent.pack() root.mainloop()
после изучения и экспериментов с кодом Брайана я создал минимальную версию проверки ввода. Следующий код будет помещать поле ввода и принимать только числовые цифры.
from tkinter import * root = Tk() def testVal(inStr,acttyp): if acttyp == '1': #insert if not inStr.isdigit(): return False return True entry = Entry(root, validate="key") entry['validatecommand'] = (entry.register(testVal),'%P','%d') entry.pack() root.mainloop()
возможно, я должен добавить, что я все еще изучаю Python, и я с удовольствием приму любые комментарии/предложения.
во время учебы ответ Брайана Оукли, что-то подсказало мне, что можно разработать гораздо более общее решение. В следующем примере представлены перечисление режимов, словарь типов и функция настройки для целей проверки. См. строку 48, например, использование и демонстрация его простоты.
#! /usr/bin/env python3 # https://stackoverflow.com/questions/4140437 import enum import inspect import tkinter from tkinter.constants import * Mode = enum.Enum('Mode', 'none key focus focusin focusout all') CAST = dict(d=int, i=int, P=str, s=str, S=str, v=Mode.__getitem__, V=Mode.__getitem__, W=str) def on_validate(widget, mode, validator): # http://www.tcl.tk/man/tcl/TkCmd/ttk_entry.htm#M39 if mode not in Mode: raise ValueError('mode not recognized') parameters = inspect.signature(validator).parameters if not set(parameters).issubset(CAST): raise ValueError('validator arguments not recognized') casts = tuple(map(CAST.__getitem__, parameters)) widget.configure(validate=mode.name, validatecommand=[widget.register( lambda *args: bool(validator(*(cast(arg) for cast, arg in zip( casts, args)))))]+['%' + parameter for parameter in parameters]) class Example(tkinter.Frame): @classmethod def main(cls): tkinter.NoDefaultRoot() root = tkinter.Tk() root.title('Validation Example') cls(root).grid(sticky=NSEW) root.grid_rowconfigure(0, weight=1) root.grid_columnconfigure(0, weight=1) root.mainloop() def __init__(self, master, **kw): super().__init__(master, **kw) self.entry = tkinter.Entry(self) self.text = tkinter.Text(self, height=15, width=50, wrap=WORD, state=DISABLED) self.entry.grid(row=0, column=0, sticky=NSEW) self.text.grid(row=1, column=0, sticky=NSEW) self.grid_rowconfigure(1, weight=1) self.grid_columnconfigure(0, weight=1) on_validate(self.entry, Mode.key, self.validator) def validator(self, d, i, P, s, S, v, V, W): self.text['state'] = NORMAL self.text.delete(1.0, END) self.text.insert(END, 'd = {!r}\ni = {!r}\nP = {!r}\ns = {!r}\n' 'S = {!r}\nv = {!r}\nV = {!r}\nW = {!r}' .format(d, i, P, s, S, v, V, W)) self.text['state'] = DISABLED return not S.isupper() if __name__ == '__main__': Example.main()