Шаг 37.
Библиотека Tkinter. Компоненты и вспомогательные классы. Стилизуемые компоненты. Компонент Entry: проверка введенного значения на правильность

    На этом шаге мы рассмотрим организацию такой проверки.

    Очень часто значение, заносимое пользователем в поле ввода или другой аналогичный компонент, требуется проверять на соответствие некоторым условиям. Таким условием может быть, например, совпадение его с каким-либо регулярным выражением.

    Реализовать такую проверку в Tkinter-приложении несложно - для этого следует выполнить перечисленные далее шаги.

  1. Определить функцию (метод), которая будет выполнять необходимую проверку и возвращать True, если введенное значение правильно, и False в противном случае. Если эта функция вернет False, попытка пользователя изменить значение в компоненте будет отвергнута.

  2. Зарегистрировать эту функцию (метод) в библиотеке Tkinter, воспользовавшись поддерживаемым всеми компонентами методом
      register(<Регистрируемая функция (метод)>). 
    
    Он вернет строковую величину - идентификатор зарегистрированной функции (метода).

  3. Указать полученный идентификатор в опции validatecommand компонента, чье значение требуется проверять.

  4. Указать в опции validate того же компонента момент времени, в который следует выполнять проверку (и, соответственно, вызывать эту функцию или метод). Момент времени задается в виде одного из следующих строковых значений:
    • "focus" - при получении или потере компонентом фокуса ввода;
    • "focusin" - при получении компонентом фокуса ввода;
    • "focusout" - при потере компонентом фокуса ввода;
    • "key" - при любом изменении значения в компоненте;
    • "all" - во всех перечисленных ранее случаях;
    • "none" - вообще не выполнять проверку (поведение по умолчанию).

    Далее приведен пример кода, создающего поле ввода для набора почтового индекса. Метод is_valid() проверяет, правильный ли индекс указан (правильный индекс должен содержать шесть цифр: от 1 до 9), для чего используется регулярное выражение. Если указан неправильный индекс, фокус ввода принудительно возвращается полю ввода, в противном случае курсор можно переместить с поля ввода:

import tkinter
import tkinter.ttk
import re

class Application(tkinter.ttk.Frame):
    def  __init__(self, master=None):
        super().__init__(master)
        # Обязательно указываем ширину и высоту контейнера посредством
        # опций width и height соответственно
        self.configure(width=200, height=100)
        self.pack(padx=4, pady=4)
        self.create_widgets()
        self.master.title("Проверка значений")
        # Запрещаем изменять размеры окна
        self.master.resizable(False, False)

    def  create_widgets(self):
        self.pre = re.compile(r"^[1-9]{6}$")
        v = self.register(self.is_valid)
        self.entValue = tkinter.ttk.Entry(self, validatecommand=v, 
             validate="focusout")
        self.entValue.pack()
        btnOK = tkinter.ttk.Button(self, text="Отправить")
        btnOK.pack()

    def  is_valid(self):
        if self.pre.match(self.entValue.get()):
            return True
        else:
            self.entValue.focus_set()
            return False
           

root = tkinter.Tk()
app = Application(master=root)
root.mainloop()
Архив с файлом можно взять здесь.

    На рисунке 1 приведен пример задания правильного значения (курсор отсутствует в поле ввода), а на рисунке 2 - курсор присутствует в поле ввода, потому что задано ошибочное значение.


Рис.1. Задано правильное значение в поле ввода


Рис.2. Задано неправильное значение в поле ввода

    Если в функции (методе), выполняющей проверку, нужно получить дополнительные сведения о значении, с которым работает пользователь, следует выполнить действия, перечисленные далее.

  1. Опции validatecommand компонента нужно присвоить кортеж, первым элементом которого станет, опять же, строковый идентификатор зарегистрированной функции (метода), а последующими - строковые обозначения данных, которые необходимо получить. Библиотека Tkinter поддерживает такие обозначения:
    • "%d" - 0, если была выполнена попытка удаления символа или выделенного фрагмента значения, 1, если была выполнена попытка вставки, -1, если проверка выполнялась в момент получения, потери фокуса ввода или изменения значения связанной с компонентом метапеременной;
    • "%i" - индекс вставленного или удаленного символа, если была выполнена попытка вставки или удаления, -1 во всех остальных случаях;
    • "%Р" - значение компонента, каким бы оно стало, если бы проверка прошла успешно;
    • "%s" - значение компонента перед его изменением;
    • "%S" - вставленный или удаленный фрагмент, None во всех остальных случаях;
    • "%v" - текущее значение опции validate;
    • "%V" - причина, вызвавшая запуск проверки:
      • "focusin" - получение фокуса,
      • "focusout" - потеря фокуса,
      • "key" - изменение значения пользователем или
      • "forced" - программное изменение значения связанной метапеременной.

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

    В качестве примера немного переделаем приведенный ранее код. Теперь получение текущего значения поля ввода выполняется через параметр метода, который выполняет проверку значения:

import tkinter
import tkinter.ttk
import re

class Application(tkinter.ttk.Frame):
    def  __init__(self, master=None):
        super().__init__(master)
        # Обязательно указываем ширину и высоту контейнера посредством
        # опций width и height соответственно
        self.configure(width=200, height=100)
        self.pack(padx=4, pady=4)
        self.create_widgets()
        self.master.title("Проверка значений")
        # Запрещаем изменять размеры окна
        self.master.resizable(False, False)

    def  create_widgets(self):
        self.pre = re.compile(r"^[1-9]{6}$")
        v = self.register(self.is_valid)
        # == Ниже измененная строка ==
        self.entValue = tkinter.ttk.Entry(self, validatecommand=(v, "%P"), 
            validate="focusout")
        self.entValue.pack()
        btnOK = tkinter.ttk.Button(self, text="Отправить")
        btnOK.pack()

    # == Ниже измененная строка ==
    def  is_valid(self, value):
        # == Ниже измененная строка ==
        if self.pre.match(value):
            return True
        else:
            self.entValue.focus_set()
            return False
           

root = tkinter.Tk()
app = Application(master=root)
root.mainloop()
Архив с файлом можно взять здесь.

    На следующем шаге мы рассмотрим виджет Label.




Предыдущий шаг Содержание Следующий шаг