Создание, изменение и проверка текста / tkinter 2
Виджет Entry представляет собой текстовый элемент на одной строке. Вместе с классами Label и Button он является одним из самых используемых в Tkinter.
Как создать текстовый элемент
Следующий пример демонстрирует, как создать форму логина с двумя экземплярами для полей username и password . Каждый символ password отображается в качестве звездочки. Кнопка Войти выводит значения в консоли, а Очистить — удаляет содержимое обоих полей, возвращая фокус в username :
import tkinter as tk
class LoginApp(tk.Tk):
def __init__(self):
super().__init__()
self.username = tk.Entry(self)
self.password = tk.Entry(self, show="*")
self.login_btn = tk.Button(self, text="Войти",
command=self.print_login)
self.clear_btn = tk.Button(self, text="Очистить",
command=self.clear_form)
self.username.pack()
self.password.pack()
self.login_btn.pack(fill=tk.BOTH)
self.clear_btn.pack(fill=tk.BOTH)
def print_login(self):
print("Логин: <>".format(self.username.get()))
print("Пароль: <>".format(self.password.get()))
def clear_form(self):
self.username.delete(0, tk.END)
self.password.delete(0, tk.END)
self.username.focus_set()
if __name__ == "__main__":
app = LoginApp()
app.mainloop()
Как работают экземпляры
Экземпляры виджетов Entry создаются в родительском окне или фрейме, будучи переданными в качестве первого аргумента. С помощью опциональных ключевых слов можно задать дополнительные свойства. У username в этом примере таких нет, а у password — аргумент show со строкой «*», который будет выводить каждый символ как звездочку.
С помощью метода get() текущий текст можно будет получить в виде строки. Это используется в методе print_login() , который выводит содержимое Entry в стандартном выводе ( stdout ).
Метод delete() принимает два аргумента, которые представляют собой диапазон символов для удаления. Важно только помнить, что индексы начинаются с 0 и не включают последний символ. Если передать только один аргумент, то удалится символ на этой позиции.
В методе clear_form() удаляется содержимое от индекса 0 до константы END , в результате чего весь контент очищается. После этого фокус возвращается в поле username .
Содержимое виджета Entry можно модифицировать с помощью метода insert() , который принимает два аргумента:
- index — позиция, куда нужно вставить текст (индекс первого — 0)
- string — строка, которая будет вставлена
Стандартный шаблон сброса содержимого на значение по умолчанию — комбинация методов delete() и insert() :
Еще один паттерн — добавление текста туда, где находится курсор. Для этого используется константа INSERT :
Как и Button класс Entry также принимает параметры relief и state для изменения стиля контура и состояния. Также стоит отметить, что вызовы delete() и insert() игнорируются, когда состояние равно «disabled» или «readonly».
Отслеживание изменений текста
Переменные Tk позволяют отправлять уведомления приложениям, когда входящие значения меняются. Есть 4 класса переменных в Tkinter: BooleanVar , DoubleVar , IntVar и StringVar . Каждый из них оборачивает значение соответствующего типа Python, который должен соответствовать типу виджета, прикрепленного к переменной.
Эта особенность особенно полезна в том случае, если нужно автоматически обновить отдельные части приложения на основе текущего состояния виджетов.
Как отслеживать изменения текста
В следующем примере экземпляр StringVar ассоциирован с Entry, у которого есть параметр textvariable . Такие переменные отслеживают операции записи с помощью метода обратного вызова show_message() :
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.var = tk.StringVar()
self.var.trace("w", self.show_message)
self.entry = tk.Entry(self, textvariable=self.var)
self.btn = tk.Button(self, text="Очистить",
command=lambda: self.var.set(""))
self.label = tk.Label(self)
self.entry.pack()
self.btn.pack()
self.label.pack()
def show_message(self, *args):
value = self.var.get()
text = "Привет, <>!".format(value) if value else ""
self.label.config(text=text)
if __name__ == "__main__":
app = App()
app.mainloop()Когда что-то вводится в этот виджет, текст метки обновляется на тот, что был составлен с помощью значения переменной Tk . Например, если ввести слово «Мир», то метка выведет Привет, Мир! . Если текст не вводить совсем, то ничего и не будет выводиться. Для демонстрации возможностей интерактивной настройки содержимого переменной была добавлена кнопка, которая очищает поле по нажатию.
Как работает изменение текста
Первые строки конструктора приложения создают экземпляр StringVar и прикрепляют функцию обратного вызова для режима записи. Валидные значения этого режима:
- w — вызывается, когда переменная пишется
- r — вызывается, когда переменная читается
- u (от unset) — вызывается, когда переменная удаляется
При вызове функция обратного вызова получает три аргумента: внутреннее имя переменной, пустую строку (она используется в других типах переменных Tk ) и режим, который запустил операцию. При объявлении его с *args эти аргументы становятся опциональными, потому что при обратном вызове значения уже не используются.
Метод get() оберток Tk возвращает текущее значение переменной, а метод set() — обновляет его. Они также уведомляют все методы прослушки ( trace ). Поэтому изменение содержимого поля с помощью графического интерфейса и нажатие кнопки Очистить запускают вызов метода show_message() .
Переменные Tk являются опциональными для виджетов поля, но они обязательны для работы других классов виджетов, таких как классы Checkbutton и Radiobutton .
Валидация текста в полях
Чаще всего поля для ввода текста представляют собой поля, которые следуют определенным правилам валидации, например, максимальная длина или определенный формат. Некоторые приложения предоставляют возможность ввода содержимого любого вида и выполняют валидацию уже после того как вся форма целиком была отправлена.
При определенных условиях нужно предотвратить возможность ввода невалидного содержимого в поле текста. Следующие примеры рассмотрят, как реализовать такое поведение с помощью параметров валидации в виджете Entry.
Как валидировать текст
Следующее приложение демонстрирует, как валидировать текст в поле ввода с помощью регулярных выражений:
import re
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.pattern = re.compile("^\w$")
self.label = tk.Label(self, text="Введите логин")
vcmd = (self.register(self.validate_username), "%i", "%P")
self.entry = tk.Entry(self, validate="key",
validatecommand=vcmd,
invalidcommand=self.print_error)
self.label.pack()
self.entry.pack(anchor=tk.W, padx=10, pady=10)
def validate_username(self, index, username):
print("Проверка символа" + index)
return self.pattern.match(username) is not None
def print_error(self):
print("Запрещенный символ в логине")
if __name__ == "__main__":
app = App()
app.mainloop()Если запустить этот скрипт и ввести не букву алфавита или цифру, то содержимое не изменится, а вместо этого будет выведено сообщение об ошибке в консоль. Это же будет происходить, если попытаться ввести больше 10 символов, поскольку регулярное выражение ограничивает общее количество.
Как работает валидация текста
Когда параметром validate является key , то валидация запускается при любом изменении содержимого. Значение по умолчанию — none , что значит, что валидации не будет.
Также значениями могут быть focusin или focusout , когда валидация выполняется при получении или потере фокуса. Значение focus выполняет проверку в обоих случаях. Во всех ситуациях валидация проходит, если установить значение all .
Функция validatecommand вызывается каждый раз при запуске валидации. Она должна возвращать true , если введенное содержимое прошло проверку. В противном случае — false .
Поскольку нужно больше информации, чтобы определить, является ли контент валидным, над функцией Python создается обертка Tcl с помощью метода register класса Widget . Затем добавляется замещение для каждого параметра, который будет передаться в функцию. В итоге эти значения группируются в кортеж. Описанное соответствует следующей строке из примера:
vcmd = (self.register(self.validate_username), "%i", "%P")
Можно использовать следующие замещения:
- %d — тип действия. 1 — добавление, 0 — удаление, -1 — остальное;
- %i — индекс вставляемой или удаляемой строки;
- %p — сущность содержимого, если изменение разрешено;
- %s — строковое содержимое до изменения;
- %s — строка, которая вставляется или удаляется;
- %v — тип текущей валидации;
- %V— тип валидации, которая запускает действие;
- %w — название виджета Entry.
Параметр invalidcommand принимает функцию, которая вызывается, когда validatecommand возвращает false . Те же замещения могут быть применены и к нему, но в данном примере классу был прямо передан метод print_error() .
Документация Tcl/Tk предполагает, что не нужно смешивать параметры validatecommand и textvariable , поскольку невалидое значение переменной Tk вообще отключит проверку. То же самое произойдет, если функция validatecommand не вернет булевое значение.