tkinter Entry validatecommand и trace_add для float, который позволяет пустой ввод и запускает функцию обновления

Вопрос или проблема

Введите или вставьте только число с плавающей запятой в tk.Entry, за исключением пустого поля, затем вызовите действие, которое передаст обновленное значение. Это должно быть универсальным.

import tkinter as tk

def float_validation(inStr, acttyp): # проверка на число с плавающей запятой
    if acttyp == '1':
        try:
            float(inStr)
            return True 
        except ValueError:
            return False
    # НЕ оценивайте actype == '0' (действие удаления)
    # Используя acttype == '0', попробуйте: float("") возвращает False
    return True

def update_from_entry(entry): # обработка пустой строки после проверки на число с плавающей запятой
    if not entry.get() == "":
        vals[strs.index(entry)].set(float(entry.get()))  
    else:
        vals[strs.index(entry)].set(0)
        
def calculate(entry): # выполнить действие после обновления ввода
    update_from_entry(entry)
    calculated_value.set(entry1_val.get() + entry2_val.get())

root = tk.Tk()  
strs = [] # создайте списки объектов для индексации друг относительно друга
vals = []

entry1_str = tk.StringVar(value="0.123") 
strs.append(entry1_str) 
entry1_str.trace_add('write', lambda a, b, c, entry=entry1_str: calculate(entry)) 
entry1_input = tk.Entry(root, textvariable=entry1_str, validate="all")
entry1_input.grid(row=0, sticky='ew')
entry1_input['validatecommand'] = entry1_input.register(float_validation), '%P', '%d'
entry1_val = tk.DoubleVar(value=float(entry1_str.get()))
vals.append(entry1_val)

entry2_str = tk.StringVar(value="0.456")
strs.append(entry2_str)
entry2_str.trace_add('write', lambda a, b, c, entry=entry2_str: calculate(entry))
entry2_input = tk.Entry(root, textvariable=entry2_str, validate="all")
entry2_input.grid(row=1, sticky='ew')
entry2_input['validatecommand'] = entry1_input.register(float_validation), '%P', '%d'
entry2_val = tk.DoubleVar(value=float(entry2_str.get()))
vals.append(entry2_val)

calculated_value = tk.DoubleVar(value=entry1_val.get() + entry2_val.get())
output = tk.Label(root, textvariable=calculated_value).grid(row=2, sticky='ew')

root.mainloop() 

Код работает, но является ли он слишком усложнённым? Это разумный способ ограничить tk.Entry только числами с плавающей запятой, вводя дополнительные шаги для обработки пустой tk.Entry, валидация которой возвращает False от float(""), при этом вызывая обновления? Я неправильно понял, как разрешить пустые (и/или вставляемые в) объекты tk.Entry?

Ответ или решение

Ваш запрос направлен на использование библиотеки Tkinter для работы с элементами ввода, в частности с tk.Entry, которая должна принимать только значения с плавающей точкой, с возможностью оставлять поле пустым. Данная задача обостряет специфику валидации ввода и обновления значений в реальном времени. Давайте детально рассмотрим ваше решение и возможные оптимизации.

Анализ существующего решения

Ваше решение включает функцию float_validation, которая проверяет, является ли введённое значение допустимым числом с плавающей точкой. При этом также предусмотрена возможность оставить поле пустым. Высокая степень модульности кода достигается благодаря использованию списка переменных и несколько StringVar и DoubleVar.

Основные элементы работы

  1. Функция валидации:
    Функция float_validation принимает строки и тип действия (ввод, удаление и т.д.). Заметно, что если действие является удалением (acttyp == '0'), валидация проходит успешно. Это выбор вполне логичен, поскольку мы не хотим блокировать удаление символов из строки.

  2. Обновление значений:
    Использование trace_add для отслеживания изменений в переменных StringVar позволяет автоматически выполнять функции при каждом изменении. Это удобно, так как не нужно явно опрашивать значение поля на каждой итерации.

  3. Обработка пустых полей:
    Метод update_from_entry корректно обрабатывает ситуацию с пустыми строками, устанавливая значение по умолчанию в 0, что удобно для дальнейших вычислений.

Оптимизации и улучшения

Ваш код может быть упрощён без потери функциональности:

  1. Упрощение обработки валидации:
    Можно прямо вернуть True для пустых строк в функции float_validation, снижая необходимость дополнительной ветвления.

  2. Шаблонизация на уровне интерфейса:
    Рассмотрите возможность создания отдельной функции для инициализации полей ввода, чтобы избежать повторения кода.

  3. Ссылка на переменные:
    Вместо того чтобы создавать отдельные списки для строк и значений (strs и vals), можно рассмотреть использование словарей для хранения переменных и их соответствующих значений, что значительно упростит доступ и модификацию.

Пример упрощенного кода

Вот упрощённая версия вашего исходного кода:

import tkinter as tk

def float_validation(inStr, acttyp):
    if acttyp == '1':
        return inStr == "" or inStr.replace('.', '', 1).isdigit()
    return True  # Если удаление, всегда возвращаем True

def update_from_entry(entry):
    entry_value = entry.get()
    vals[strs.index(entry)].set(float(entry_value) if entry_value else 0.0)

def calculate(entry):
    update_from_entry(entry)
    calculated_value.set(entry1_val.get() + entry2_val.get())

root = tk.Tk()
strs = []
vals = []

def create_entry(row, initial_value):
    entry_str = tk.StringVar(value=initial_value)
    entry_str.trace_add('write', lambda a, b, c: calculate(entry_str))
    entry_input = tk.Entry(root, textvariable=entry_str, validate="all")
    entry_input.grid(row=row, sticky='ew')
    entry_input['validatecommand'] = (entry_input.register(float_validation), '%P', '%d')
    entry_val = tk.DoubleVar(value=float(initial_value))
    strs.append(entry_str)
    vals.append(entry_val)
    return entry_input, entry_val

entry1_input, entry1_val = create_entry(0, "0.123")
entry2_input, entry2_val = create_entry(1, "0.456")

calculated_value = tk.DoubleVar(value=entry1_val.get() + entry2_val.get())
output = tk.Label(root, textvariable=calculated_value).grid(row=2, sticky='ew')

root.mainloop()

Заключение

Ваш подход к решению задачи в целом правильный, однако, рекомендуемые оптимизации могут упростить код и сделать его более читабельным, что особенно важно в контексте поддерживаемых проектов. Использование более динамичных структур, таких как словари, также может облегчить изменение и масштабирование системы в будущем.

Оцените материал
Добавить комментарий

Капча загружается...