Полное руководство по использованию поля ввода в tkinter
Виджет Entry (окно ввода) в библиотеке tkinter используется для однострочного ввода текста. Он является основным элементом графического интерфейса, позволяющим пользователю вводить данные. В статье рассматриваются различные способы настройки и использования Entry, включая скрытый ввод, проверку символов, подсказки и маски.
Основное использование окна ввода (Entry)
Самый простой способ создать окно ввода - воспользоваться классом Entry и разместить его в родительском контейнере. Основные методы для работы со значением: get() для получения текста, insert() для вставки и delete() для удаления.
import tkinter as tk
root = tk.Tk()
root.title("Пример Entry")
entry = tk.Entry(root)
entry.pack(padx=10, pady=10)
def show_text():
text = entry.get()
label.config(text=f"Введено: {text}")
button = tk.Button(root, text="Показать", command=show_text)
button.pack()
label = tk.Label(root, text="")
label.pack()
root.mainloop()Python окно ввода (окно ввода в tkinter)
При запуске откроется окно с полем ввода и кнопкой. После ввода текста и нажатия кнопки под полем появится надпись «Введено: ...»
Типичная ошибка: попытка вызвать get() до того, как окно отобразится (в самом начале программы) - возвращается пустая строка, так как пользователь ещё ничего не ввёл. Решение: вызывать get() только в ответ на событие (например, нажатие кнопки или потерю фокуса).
Как сделать окно ввода, в котором текст скрыт (поле для пароля)?
Для скрытия вводимых символов используется параметр show. Значение строки определяет символ-заменитель, например show="*".
import tkinter as tk
root = tk.Tk()
root.title("Пароль")
password_entry = tk.Entry(root, show="•", width=30)
password_entry.pack(pady=10)
def check_password():
pwd = password_entry.get()
if pwd == "secret":
label.config(text="Доступ разрешён", fg="green")
else:
label.config(text="Неверный пароль", fg="red")
btn = tk.Button(root, text="Войти", command=check_password)
btn.pack()
label = tk.Label(root, text="")
label.pack()
root.mainloop()
При вводе символов они отображаются как кружки (•). Получить реальное значение можно через get().
Проблема: копирование текста из такого поля (Ctrl+C) может скопировать реальные символы, что является риском безопасности. Для защиты от этого нужно отключить возможность копирования с помощью отвязки событий или использования сторонних библиотек.
Как реализовать проверку вводимых символов (только цифры, длина не более 5)?
tkinter предоставляет механизм валидации через параметры validate, validatecommand и invalidcommand. Валидация выполняется при каждом изменении содержимого или потере фокуса.
import tkinter as tk
def validate_number(new_value):
# new_value - строка, которая будет вставлена
if new_value == "":
return True
if new_value.isdigit() and len(new_value) <= 5:
return True
return False
root = tk.Tk()
root.title("Только цифры, макс 5")
vcmd = (root.register(validate_number), '%P')
entry = tk.Entry(root, validate="key", validatecommand=vcmd)
entry.pack(pady=10)
label = tk.Label(root, text="Введите до 5 цифр")
label.pack()
root.mainloop()
Поле принимает только цифры и не даёт ввести более 5 символов. При попытке ввести букву или шестую цифру символ игнорируется.
Частая ошибка: забывают передать '%P' и другие специальные подстановки. Если функция валидации возвращает False, вставка отменяется. При использовании validate="key" функция вызывается при каждом нажатии клавиши.
Как добавить подсказку (placeholder) в поле Entry?
В tkinter нет встроенного placeholder, но его можно имитировать с помощью установки начального текста серым цветом и очисткой при фокусе.
import tkinter as tk
def on_focus_in(event):
if entry.get() == "Введите email":
entry.delete(0, tk.END)
entry.config(fg='black')
def on_focus_out(event):
if entry.get() == "":
entry.insert(0, "Введите email")
entry.config(fg='grey')
root = tk.Tk()
root.title("Placeholder")
entry = tk.Entry(root, fg='grey')
entry.insert(0, "Введите email")
entry.bind("<FocusIn>", on_focus_in)
entry.bind("<FocusOut>", on_focus_out)
entry.pack(pady=10)
root.mainloop()
При запуске в поле отображается серый текст «Введите email». При клике он исчезает, цвет меняется на чёрный. Если поле остаётся пустым при потере фокуса, подсказка возвращается.
Проблема: если пользователь ввёл текст, совпадающий с подсказкой, а затем убрал фокус, подсказка не должна появляться. Необходимо добавить дополнительную проверку или использовать отдельный флаг.
Как реализовать маску ввода (например, для номера телефона)?
Для ограничения формата ввода можно комбинировать валидацию с форматированием. Ниже пример, который вставляет дефис после третьего символа и позволяет вводить только цифры и дефис.
import tkinter as tk
def validate_phone(new_value):
if new_value == "":
return True
# Разрешены только цифры и дефис
allowed = set("0123456789-")
if not set(new_value).issubset(allowed):
return False
# Автоматическое добавление дефиса после третьего символа
if len(new_value) == 3 and new_value[2] != '-':
# Не можем напрямую изменить текст в валидации, поэтому используем после валидации
pass
return True
def format_phone(event):
phone = entry.get()
if len(phone) == 3 and phone[2] != '-':
entry.insert(3, '-')
root = tk.Tk()
root.title("Маска телефона")
vcmd = (root.register(validate_phone), '%P')
entry = tk.Entry(root, validate="key", validatecommand=vcmd)
entry.bind('<KeyRelease>', format_phone)
entry.pack(pady=10)
root.mainloop()
При вводе третьего символа автоматически добавляется дефис. Поле принимает только цифры и дефис.
Сложность: валидация и форматирование часто конфликтуют. Использование привязки к KeyRelease после валидации может привести к зацикливанию или неправильной позиции курсора. Более надёжный способ - переопределить методы insert и delete пользовательского подкласса.
Расширенные примеры использования Entry
Автодополнение (Autocomplete) на основе Entry и Listbox
import tkinter as tk
class AutocompleteEntry(tk.Entry):
def __init__(self, master, completions, *args, **kwargs):
super().__init__(master, *args, **kwargs)
self.completions = completions
self.listbox = None
self.bind('<KeyRelease>', self.check)
self.bind('<FocusOut>', self.hide_listbox)
def check(self, event):
typed = self.get()
if typed == '':
self.hide_listbox()
return
matches = [c for c in self.completions if c.lower().startswith(typed.lower())]
if matches:
self.show_listbox(matches)
else:
self.hide_listbox()
def show_listbox(self, matches):
if self.listbox is None:
self.listbox = tk.Listbox(self.master, height=4)
self.listbox.bind('<ButtonRelease-1>', self.select)
self.listbox.bind('<Return>', self.select)
else:
self.listbox.delete(0, tk.END)
for item in matches:
self.listbox.insert(tk.END, item)
# Размещаем listbox сразу под Entry
x = self.winfo_x()
y = self.winfo_y() + self.winfo_height()
self.listbox.place(x=x, y=y)
def hide_listbox(self, event=None):
if self.listbox:
self.listbox.place_forget()
def select(self, event):
if self.listbox:
selection = self.listbox.get(tk.ACTIVE)
self.delete(0, tk.END)
self.insert(0, selection)
self.hide_listbox()
root = tk.Tk()
root.title("Автодополнение")
cities = ["Москва", "Минск", "Мурманск", "Магадан", "Мюнхен"]
entry = AutocompleteEntry(root, cities, width=30)
entry.pack(padx=10, pady=10)
root.mainloop()
При вводе буквы «М» появляется выпадающий список с совпадениями. Клик или Enter подставляет выбранный город.
Валидация через StringVar и trace (реагирование на изменение)
import tkinter as tk
def validate_text(*args):
value = var.get()
# Оставляем только буквы и пробелы
filtered = ''.join(c for c in value if c.isalpha() or c.isspace())
if filtered != value:
var.set(filtered)
root = tk.Tk()
root.title("Trace валидация")
var = tk.StringVar()
var.trace_add('write', validate_text)
entry = tk.Entry(root, textvariable=var, width=30)
entry.pack(pady=10)
label = tk.Label(root, text="Только буквы и пробелы")
label.pack()
root.mainloop()
При вводе цифр или спецсимволов они автоматически удаляются, изменяя значение StringVar.
Кастомное числовое поле с ограничением диапазона
import tkinter as tk
class NumericEntry(tk.Entry):
def __init__(self, master, min_val=0, max_val=100, *args, **kwargs):
super().__init__(master, *args, **kwargs)
self.min_val = min_val
self.max_val = max_val
self.vcmd = (master.register(self.validate_numeric), '%P')
self.config(validate='key', validatecommand=self.vcmd)
def validate_numeric(self, new_value):
if new_value == '':
return True
try:
value = int(new_value)
if self.min_val <= value <= self.max_val:
return True
else:
return False
except ValueError:
return False
root = tk.Tk()
root.title("Числовое поле 0-100")
num_entry = NumericEntry(root, min_val=0, max_val=100, width=10)
num_entry.pack(pady=10)
def show_value():
val = num_entry.get()
if val.isdigit():
label.config(text=f"Значение: {val}")
else:
label.config(text="Поле пустое или не число")
btn = tk.Button(root, text="Получить", command=show_value)
btn.pack()
label = tk.Label(root, text="")
label.pack()
root.mainloop()
Поле принимает только целые числа от 0 до 100. Остальные символы игнорируются.