Вопрос или проблема
Введите или вставьте только число с плавающей запятой в 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
.
Основные элементы работы
-
Функция валидации:
Функцияfloat_validation
принимает строки и тип действия (ввод, удаление и т.д.). Заметно, что если действие является удалением (acttyp == '0'
), валидация проходит успешно. Это выбор вполне логичен, поскольку мы не хотим блокировать удаление символов из строки. -
Обновление значений:
Использованиеtrace_add
для отслеживания изменений в переменныхStringVar
позволяет автоматически выполнять функции при каждом изменении. Это удобно, так как не нужно явно опрашивать значение поля на каждой итерации. -
Обработка пустых полей:
Методupdate_from_entry
корректно обрабатывает ситуацию с пустыми строками, устанавливая значение по умолчанию в0
, что удобно для дальнейших вычислений.
Оптимизации и улучшения
Ваш код может быть упрощён без потери функциональности:
-
Упрощение обработки валидации:
Можно прямо вернутьTrue
для пустых строк в функцииfloat_validation
, снижая необходимость дополнительной ветвления. -
Шаблонизация на уровне интерфейса:
Рассмотрите возможность создания отдельной функции для инициализации полей ввода, чтобы избежать повторения кода. -
Ссылка на переменные:
Вместо того чтобы создавать отдельные списки для строк и значений (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()
Заключение
Ваш подход к решению задачи в целом правильный, однако, рекомендуемые оптимизации могут упростить код и сделать его более читабельным, что особенно важно в контексте поддерживаемых проектов. Использование более динамичных структур, таких как словари, также может облегчить изменение и масштабирование системы в будущем.