Полное руководство по использованию поля ввода в tkinter

Раздел: Графические интерфейсы -> элементы 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. Остальные символы игнорируются.

окно ввода в tkinter - comments

En
Python окно ввода (python)