Python tkinter grid методы
Метод grid() позволяет поместить виджет в определенную ячейку условной сетки или грида.
Метод grid применяет следующие параметры:
- column : номер столбца, отсчет начинается с нуля
- row : номер строки, отсчет начинается с нуля
- columnspan : сколько столбцов должен занимать элемент
- rowspan : сколько строк должен занимать элемент
- ipadx и ipady : отступы по горизонтали и вертикали соответственно от границ элемента до его содержимого
- padx и pady : отступы по горизонтали и вертикали соответственно от границ ячейки грида до границ элемента
- sticky : выравнивание элемента в ячейке, если ячейка больше элемента. Может принимать значения n, e, s, w, ne, nw, se, sw, которые указывают соответствующее направление выравнивания
Установка ячейки виджета
Например, определим грид из 9 кнопок:
from tkinter import * from tkinter import ttk root = Tk() root.title("METANIT.COM") root.geometry("250x200") for r in range(3): for c in range(3): btn = ttk.Button(text=f"(,)") btn.grid(row=r, column=c) root.mainloop()
Здесь в цикле создается девять кнопок, каждая из которых помещается в свою ячейку. В итоге у нас получится следующий грид
По умолчанию для каждой ячейки выделяется столько места, сколько необходимо для виджета в ней. Соответственно мы получаем небольшую таблицу и много пустого места вне грида, что, возможно, смотрится не лучшим образом. И ситуация усугубляется, если мы попробуем растянуть окно — появится еще больше пустого пространства. Чтоюбы решить эту проблему, надо сконфигурировать грид у контейнера.
Конфигурация грида
Для конфигурации грида в контейнере применяются два метода:
container.columnconfigure(index, weight) container.rowconfigure(index, weight)
Метод columnconfigure() настраивает столбец. В качестве параметра index метод получает индекс столбца, а через параметр weight устанавливает его вес. Столбцы распределяются по всей ширине контейнера в соответствии со своим весом.
Метод rowconfigure() настраивает строку аналогичным образом. В качестве параметра index метод получает индекс строки, а через параметр weight устанавливает ее вес. Строки распределяются по всей длине контейнера в соответствии со своим весом.
Например, изменим код выше, добавив конфигурацию строк и столбцов:
from tkinter import * from tkinter import ttk root = Tk() root.title("METANIT.COM") root.geometry("250x200") for c in range(3): root.columnconfigure(index=c, weight=1) for r in range(3): root.rowconfigure(index=r, weight=1) for r in range(3): for c in range(3): btn = ttk.Button(text=f"(,)") btn.grid(row=r, column=c) root.mainloop()
Поскольку у нас три строки, для упрощения в цикле для каждой строки устанавливаем вес 1. То есть в итоге каждая из трех строк будет занимать треть высоты контейнера (пространство_контейнера / сумму всех весов строк).
Аналогично в цикле для каждого столбца устанавливаем вес 1. То есть в итоге каждый из трех столбец будет занимать треть ширины контейнера.
Отступы
Параметры padx и pady повзвозяют установить отступы по горизонтали и вертикали соответственно от границ ячейки грида до границ виджета, а ipadx и ipady — отступы по горизонтали и вертикали соответственно от границ виджета до его содержимого
from tkinter import * from tkinter import ttk root = Tk() root.title("METANIT.COM") root.geometry("250x200") for c in range(3): root.columnconfigure(index=c, weight=1) for r in range(3): root.rowconfigure(index=r, weight=1) for r in range(3): for c in range(3): btn = ttk.Button(text=f"(,)") btn.grid(row=r, column=c, ipadx=6, ipady=6, padx=4, pady=4) root.mainloop()
В данном случае внешние отсуты равны 4 единиц, а внутренние — 6 единицам.
Для параметров padx и pady можно установить отступы с двух сторон в виде списка:
btn.grid(row=r, column=c, ipadx=6, ipady=6, padx=[15, 4], pady=4)
Здесь внешний отступ слева равен 10, а справа — 4 единицам.
Объединение ячеек
Параметр columnspan указывает, столько столбцов, а параметр
rowspan сколько строк должен занимать виджет. То есть с помощью подобных параметров мы можем объединить ячейки.
Растяжение на два столбца:
from tkinter import * from tkinter import ttk root = Tk() root.title("METANIT.COM") root.geometry("250x200") for c in range(2): root.columnconfigure(index=c, weight=1) for r in range(2): root.rowconfigure(index=r, weight=1) btn1 = ttk.Button(text="button 1") # columnspan=2 - растягиваем на два столбца btn1.grid(row=0, column=0, columnspan=2, ipadx=70, ipady=6, padx=5, pady=5) btn3 = ttk.Button(text="button 3") btn3.grid(row=1, column=0, ipadx=6, ipady=6, padx=5, pady=5) btn4 = ttk.Button(text="button 4") btn4.grid(row=1, column=1, ipadx=6, ipady=6, padx=5, pady=5) root.mainloop()
from tkinter import * from tkinter import ttk root = Tk() root.title("METANIT.COM") root.geometry("250x200") for c in range(2): root.columnconfigure(index=c, weight=1) for r in range(2): root.rowconfigure(index=r, weight=1) btn2 = ttk.Button(text="button 2") # rowspan=2 - растягиваем на две строки btn2.grid(row=0, column=1, rowspan=2, ipadx=6, ipady=55, padx=5, pady=5) btn1 = ttk.Button(text="button 1") btn1.grid(row=0, column=0, ipadx=6, ipady=6, padx=5, pady=5) btn3 = ttk.Button(text="button 3") btn3.grid(row=1, column=0, ipadx=6, ipady=6, padx=5, pady=5) root.mainloop()
Выравнивание
Параметр sticky задает выравнивание виджета в ячейке, если размер ячейки больше размера этого виджета. Этот параметр может принимать следующие значения:
- n : положение вверху по центру
- e : положение в правой части контейнера по центру
- s : положение внизу по центру
- w : положение в левой части контейнера по центру
- nw : положение в верхнем левом углу
- ne : положение в верхнем правом углу
- se : положение в нижнем правом углу
- sw : положение в нижнем левом углу
- ns : растяжение по вертикали
- ew : растяжение по горизонтали
- nsew : растяжение по горизонтали и вертикали
По умолчанию виджет позиционируется по центру ячейки
Наглядно растяжение по вертикали и горизонтали
Стоит отметить, что значение в кавычках для параметра anchor передается в нижнем регистре, без кавычек — в верхнем регистре
Например, растянем виджет по всему пространству ячейки (значение NSEW):
from tkinter import * from tkinter import ttk root = Tk() root.title("METANIT.COM") root.geometry("250x200") for c in range(3): root.columnconfigure(index=c, weight=1) for r in range(3): root.rowconfigure(index=r, weight=1) for r in range(3): for c in range(3): btn = ttk.Button(text=f"(,)") btn.grid(row=r, column=c, ipadx=6, ipady=6, padx=4, pady=4, sticky=NSEW) root.mainloop()
Метод 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