# Метод grid() — сетка
Метод grid() применяет другой подход к позиционированию элементов, нежели метод place() , позволяя поместить элемент в определенную ячейку условной сетки или грида.
Grid() не растягивает виждеты, находящиеся в нем, а всегда занимает минимально необходимое пространство, необходимое для виджета.
Метод grid() применяет следующие параметры:
- column : номер столбца, отсчет начинается с нуля
- row : номер строки (ряда), отсчет начинается с нуля
- columnspan : сколько столбцов должен занимать элемент
- rowspan : сколько строк (рядов) должен занимать элемент
- ipadx и ipady : отступы по горизонтали и вертикали соответственно от границ элемента до его текста
- padx и pady : отступы по горизонтали и вертикали соответственно от границ ячейки грида до границ элемента
- sticky : выравнивание элемента в ячейке, если ячейка больше элемента. Может принимать значения: N, E, S, W, NE, NW, SE, SW, NSEW — они указывают соответствующее направление выравнивания
Начальный пример демонстрации позиционирования с помощью сетки:
from tkinter import * root = Tk() root.title("Welcome to grid app!") root.geometry('350x200') label = Label(root, text="Hello!") label.grid(column=0, row=0) button = Button(root, text="Click Me!") button.grid(column=1, row=0) root.mainloop()
Следующий пример позволяет понять, как расположить элементы на сетке в виде шахматной доски:
from tkinter import * root = Tk() root.title("Welcome to grid app!") label = Label(root, text="Hello!") label.grid(column=1, row=0) button_1 = Button(root, text="Left") button_1.grid(column=0, row=0) button_2 = Button(root, text="Right") button_2.grid(column=2, row=0) button_3 = Button(root, text="Bottom") button_3.grid(column=1, row=1) root.mainloop()
Пример окна для ввода логина и пароля:
from tkinter import * root = Tk() root.title("Welcome to the second entry app") label_login = Label(root, text="Login") label_login.grid(column=0, row=0, sticky=E) field_login = Entry(root, width=10) field_login.grid(column=1, row=0) label_pass = Label(root, text="Password") label_pass.grid(column=0, row=1, sticky=E) field_pass = Entry(root, width=10) field_pass.grid(column=1, row=1) button = Button(root, text="Enter") button.grid(column=0, row=2, columnspan=2, sticky=NSEW) root.mainloop()
# Упражнения
- Для дальнейшего переиспользования кода, создайте новый файл с названием app_calculator_fields_grid.py . Используя метод grid() напишите программу состоящую из:
- однострочного текстового поля,
- метки с отображением знака «+»,
- второго однострочного текстового поля,
- кнопкой «=», при нажатии на которую результат вычисления выводиться в третье текстовое поле,
- третьего однострочного тестового поля.
- Добавьте проверку деления на 0. С выводом сообщения об ошибке, в удобное для пользователя место. Консольный вывод сообщения об ошибке исключить.
- Добавить многострочное текстовое поле вдоль правого края доски.
- Выводить в текстовое поле координаты нажатых кнопок: A1, B3 и т.д.
- Реализуйте правильную расстановку запятых: если напечатано только одно значение, запятая не ставиться. Добавление следующих записей происходит через запятую.
- Реализовать вставку текста, можно, воспользовавшись кодом:
text = Text(root) text.insert(END, "Вставка текста в конец.") text.pack() print(text.get(1.0, END))
Метод grid
Grid является одним из трех менеджеров геометрии в Tkinter (другими являются уже рассмотренный ранее Pack, а также Place). У всех виджетов есть соответствующий данному менеджеру метод grid . «Grid» с английского переводится как «сетка», однако по смыслу правильнее говорить о таблице.
Табличный способ размещения предпочтителен из-за его гибкости и удобства, когда дело доходит до разработки относительно сложных интерфейсов. Grid позволяет избежать использования множества фреймов, что неизбежно в случае упаковщика Pack.
При размещении виджетов методом grid родительский контейнер (обычно это окно) условно разделяется на ячейки подобно таблице. Адрес каждой ячейки состоит из номера строки и номера столбца. Нумерация начинается с нуля. Ячейки можно объединять как по вертикали, так и по горизонтали.
На рисунке пунктир обозначает объединение ячеек. Общая ячейка в таком случае обозначается адресом первой.
Никаких предварительных команд по разбиению родительского виджета на ячейки не выполняется. Tkinter делает это сам, исходя из указанных позиций виджетов.
Размещение виджета в той или иной ячейке задается через аргументы row и column , которым присваиваются соответственно номера строки и столбца. Чтобы объединить ячейки по горизонтали, используется атрибут columnspan , которому присваивается количество объединяемых ячеек. Опция rowspan объединяет ячейки по вертикали.
Пусть надо запрограммировать такой GUI:
Представим данный интерфейс в виде таблицы и пронумеруем ячейки, в которых будут располагаться виджеты:
from tkinter import * root = Tk() Label(text="Имя:").grid(row=0, column=0) Entry(width=30).grid(row=0, column=1, columnspan=3) Label(text="Столбцов:").grid(row=1, column=0) Spinbox(width=7, from_=1, to=50).grid(row=1, column=1) Label(text="Строк:").grid(row=1, column=2) Spinbox(width=7, from_=1, to=100).grid(row=1, column=3) Button(text="Справка").grid(row=2, column=0) Button(text="Вставить").grid(row=2, column=2) Button(text="Отменить").grid(row=2, column=3) root.mainloop()
Примечание. В примере используются виджеты класса Spinbox , которые не рассматривались в курсе. Spinbox похож на Entry , но для него задается список принимаемых значений, и имеется подобие скроллера.
Выполнив приведенный выше программный код, получим:
Похоже, но не совсем то, что хотелось. Теперь на помощь должны прийти другие свойства метода grid . У него, также как у pack , имеются атрибуты для задания внешних и внутренних отступов ( padx , pady , ipadx , ipady ).
Кроме этого есть атрибут sticky (липкий), который принимает значения направлений сторон света (N, S, W, E, NW, NE, SW, SE). Если, например, указать NW, то виджет прибьет к верхнему левому углу ячейки. Виджеты можно растягивать на весь объем ячейки ( sticky=N+S+W+E ) или только по одной из осей ( N+S или W+E ). Эффект от «липучки» заметен, только если виджет меньше ячейки.
from tkinter import * root = Tk() Label(text="Имя:")\ .grid(row=0, column=0, sticky=W, pady=10, padx=10) Entry()\ .grid(row=0, column=1, columnspan=3, sticky=W+E, padx=10) Label(text="Столбцов:")\ .grid(row=1, column=0, sticky=W, padx=10, pady=10) Spinbox(width=7, from_=1, to=50)\ .grid(row=1, column=1, padx=10) Label(text="Строк:")\ .grid(row=1, column=2, sticky=E) Spinbox(width=7, from_=1, to=100)\ .grid(row=1, column=3, sticky=E, padx=10) Button(text="Справка").grid(row=2, column=0, pady=10, padx=10) Button(text="Вставить").grid(row=2, column=2) Button(text="Отменить").grid(row=2, column=3, padx=10) root.mainloop()
С помощью методов grid_remove и grid_forget можно сделать виджет невидимым. Отличие между этими методами лишь в том, что grid_remove запоминает прежнее положение виджета. Поэтому для его отображения в прежней ячейки достаточно применить grid без аргументов. После grid_forget потребуется заново конфигурировать положение виджета.
from tkinter import * def rem(): global l1_flag if l1_flag == 1: l1.grid_remove() l1_flag = 0 else: l1.grid() l1_flag = 1 def forg(): global l2_flag if l2_flag == 1: l2.grid_forget() l2_flag = 0 else: l2.grid(row=1) l2_flag = 1 root = Tk() l1_flag = 1 l2_flag = 1 l1 = Label(width=5, height=3, bg='blue') l2 = Label(width=5, height=3, bg='green') b1 = Button(bg='lightblue', command=rem) b2 = Button(bg='lightgreen', command=forg) l1.grid(row=0) l2.grid(row=1) b1.grid(row=2) b2.grid(row=3) root.mainloop()
В данной программе голубая метка после удаления будет появляться в том же месте, где была до этого, несмотря на то, что в функции rem к ней применяется метод grid без настроек. В отличие от нее зеленая метка, если ей не указать место размещения после удаления, появлялась бы под кнопками.
Скрытие виджетов бывает необходимо в тех случаях, когда, например, от выбора пользователя в одной части интерфейса зависит, какие виджеты появятся в другой.
Практическая работа
Перепрограммируйте второе окно из практической работы предыдущего урока, используя метод grid .
Курс с примерами решений практических работ: pdf-версия
Tkinter. Программирование GUI на Python