Учебник Tkinter - управление макетами
В предыдущих разделах мы представили несколько типов виджетов Tkinter, таких как label, button, выпадающее меню и др. Между тем, мы также вкратце рассказали о том, как раскладывать эти виджеты в окне программы. Это ключевой момент, который вы узнаете в этом разделе - методы управления геометрией Tkinter.
В Tkinter есть три метода управления геометрией, то есть пакет
, сетка
и место
. Давайте рассмотрим их один за другим.
Tkinter pack
, grid
и lace
- метод раскладки
Метод pack
, как буквально указано, упаковывает виджет в оконную рамку после его создания. Мы столкнулись с этим методом компоновки в разделе Tkinter Label, где также перечислены все опции pack
.
Мы покажем, как компоновать виджеты методом pack
(также его опции). Несколько примеров помогут продемонстрировать правильную конфигурацию.
Tkinter pack
Layout - Relative Position
import tkinter as tk
app = tk.Tk()
app.geometry('300x200')
buttonW = tk.Button(app, text="West", width=15)
buttonW.pack(side='left')
buttonE = tk.Button(app, text="East", width=15)
buttonE.pack(side='right')
app.mainloop()
Запустите программу, у вас появится такое окно,
Как видно, buttonWest
щёлкает на левой стороне окна, а buttonEast
щёлкает на правой стороне. Вы можете попробовать масштабировать размер окна внизу, но вы увидите, что они все равно будут цепляться за боковые стороны окна и относительное положение не изменится.
buttonW.pack(side='left')
У side
есть четыре варианта -
top
bottom
left
right
Он помещает виджет на side
окна. Как показано в примере, buttonW
расположена с левой стороны окна, потому что side='left'
, в то время как buttonE
расположена с правой стороны окна, потому что side='right'
.
Теперь у нас есть интересный сценарий, что произойдет, если два виджета будут иметь одно и то же свойство side
, как будет раскладка?
Попробуйте ответить сами или проверьте, запустив следующие коды.
import tkinter as tk
app = tk.Tk()
app.geometry('300x200')
buttonW = tk.Button(app, text="West", width=15)
buttonW.pack(side='left')
buttonE1 = tk.Button(app, text="East 1", width=15)
buttonE1.pack(side='right')
buttonE2 = tk.Button(app, text="East 2", width=15)
buttonE2.pack(side='right')
app.mainloop()
Tkinter pack
для добавления внутренней и внешней подкладки виджета
В некоторых случаях необходимо добавить подкладку внутри или снаружи виджета, чтобы было меньше заторов между виджетами, а также между текстом виджета и границами виджета. Теперь Вам нужны такие опции, как padx
, pady
, ipadx
и ipady
.
import tkinter as tk
app = tk.Tk()
app.geometry('300x200')
buttonW = tk.Button(app, text="West")
buttonW.pack(side='left', ipadx=20, padx=30)
buttonE = tk.Button(app, text="East")
buttonE.pack(side='right', ipadx=20, padx=30)
app.mainloop()
Обе кнопки добавляют внутренние 20 единиц набивки и внешние 30 единиц в x
, при этом единица измерения является пиксельной, но не шириной одного символа.
Tkinter pack
Макет Заполнение в направлении х, у
Следующая реализация кода может автоматически заполнить размер виджета той же шириной или той же высотой, что и окно, а при увеличении окна размер элемента управления может автоматически изменяться вместе с размером окна.
import tkinter as tk
app = tk.Tk()
app.geometry('300x200')
buttonX = tk.Button(app, text="Fill X", bg="red", height=5)
buttonX.pack(fill='x')
buttonY = tk.Button(app, text="Fill Y", bg="green", width=10)
buttonY.pack(side='left', fill='y')
app.mainloop()
butonX.pack(fill='x')
означает, что buttonX
заполнит ширину всего окна. Аналогично, fill='y'
заполнит высоту всего окна, а тем временем fill='both'
заполнит и ширину, и высоту.
Tkinter pack
Вариант раскладки expand
- автоматически развернется
Выше опция fill=
автоматически заполнит виджет в направлении x
и/или y
при изменении размера окна. Другое похожее требование - как автоматически отобразить все содержимое, если виджет включает в себя несколько опций, например, список?
import tkinter as tk
import calendar
app = tk.Tk()
buttonX = tk.Button(app, text="Label ", bg="blue", height=5)
buttonX.pack(fill='x')
listboxA = tk.Listbox(app, width=10)
listboxA.pack(fill='both', expand=1)
for i in range(1,13):
listboxA.insert(tk.END, calendar.month_name[i])
app.mainloop()
Когда expand=True
или expand=1
, в окне списка будут перечислены все элементы, от Января
до Декабря
, как показано в вышеприведенном примере.
Если expand
установлен как False
, то по умолчанию в поле списка будут показаны только первые 10 элементов. Вам нужно использовать мышь или клавиши направлений, чтобы показать скрытые элементы после того, как поле списка выбрано.
listboxA.pack(fill='both', expand=0)
expand=0
отключает поле списка для автоматического показа всех элементов.
Tkinter grid
Метод раскладки
Tkinter grid
- это еще один, а также самый важный метод геометрии макета. Этому методу следует научиться, если вы хотите изучить только один единственный метод среди всех менеджеров по геометрии.
grid
часто используется в диалоговых окнах, и вы можете разместить виджеты, основываясь на координатах положения сетки. Метод компоновки grid
может иметь стабильные относительные позиции всех виджетов.
Следующий пример создаст относительно сложный GUI по сравнению с вышеприведенными примерами, который использует как можно больше опций grid
, которые будут объяснены в следующих разделах.
import tkinter as tk
app = tk.Tk()
labelWidth = tk.Label(app,
text = "Width Ratio")
labelWidth.grid(column=0, row=0, ipadx=5, pady=5, sticky=tk.W+tk.N)
labelHeight = tk.Label(app,
text = "Height Ratio")
labelHeight.grid(column=0, row=1, ipadx=5, pady=5, sticky=tk.W+tk.S)
entryWidth = tk.Entry(app, width=20)
entryHeight = tk.Entry(app, width=20)
entryWidth.grid(column=1, row=0, padx=10, pady=5, sticky=tk.N)
entryHeight.grid(column=1, row=1, padx=10, pady=5, sticky=tk.S)
resultButton = tk.Button(app, text = 'Get Result')
resultButton.grid(column=0, row=2, pady=10, sticky=tk.W)
logo = tk.PhotoImage(file='python.gif')
labelLogo = tk.Label(app, image=logo)
labelLogo.grid(row=0, column=2, columnspan=2, rowspan=2,
sticky=tk.W+tk.E+tk.N+tk.S, padx=5, pady=5)
app.mainloop()
Tkinter grid
column
и row
опции
labelWidth.grid(column=0, row=0, ipadx=5, pady=5, sticky=tk.W+tk.N)
Каждый виджет должен быть помещен в абсолютную ячейку методом компоновки grid
. Координаты ячеек определяются column
и row
.
Виджет labelWidth
помещается в ячейку позиции (0, 0)
. Координата начинается с верхнего левого угла окна.
Варианты ipadx
, ipady
, padx
и pady
такие же, как и в методе pack
.
Опция Tkinter grid
sticky
sticky
определяет, как виджет прилипает к ячейке, когда виджет меньше ячейки.
sticky |
Значение |
---|---|
W |
держаться левее |
E |
держаться правой руки |
N |
держаться сверху |
S |
держаться дна |
Опция по умолчанию sticky
является центральной, т.е. W+E+N+S
.
Опции Tkinter columnspan
и rowspan
labelLogo.grid(row=0, column=2, columnspan=2, rowspan=2,
sticky=tk.W+tk.E+tk.N+tk.S, padx=5, pady=5)
Координата ячейки labelLogo
- (column=2, row=0)
и размер логотипа относительно велик, поэтому он соотносится с размером ячейки 2x2
. columnspan=2
и rowspan=2
означает, что виджет имеет развороты двух ячеек как в направлении X
, так и в направлении Y
, начиная с положения виджета.
Метод Tkinter place
Метод
Метод Tkinter place
помещает виджет в абсолютное или относительное положение в окне. Мы по-прежнему используем тот же подход, что и выше для введения опций этого метода компоновки.
import tkinter as tk
app = tk.Tk()
app.geometry('300x300')
labelA = tk.Label(app, text = "Label (0, 0)", fg="blue", bg="#FF0")
labelB = tk.Label(app, text = "Label (20, 20)", fg="green", bg="#300")
labelC = tk.Label(app, text = "Label (40, 50)", fg="black", bg="#f03")
labelD = tk.Label(app, text = "Label (0.5, 0.5)", fg="orange", bg="#0ff")
labelA.place(x=0, y=0)
labelB.place(x=20, y=20)
labelC.place(x=40, y=50)
labelD.place(relx=0.5, rely=0.5)
app.mainloop()
Tkinter place
Абсолютная позиция
labelA.place(x=0, y=0)
labelB.place(x=20, y=20)
Опции x=
и y=
в place
определяют абсолютные позиции виджета, которые имеют единицу измерения в виде пикселя. Например, lableB.place(x=20, y=20)
означает, что labelB
помещается в координату (20, 20)
.
Tkinter place
относительное положение
Недостатком абсолютной позиции является то, что если в окне размещены другие виджеты с относительными позициями, то при масштабировании окна виджет, использующий абсолютное расположение позиций, возможно, будет иметь перекрытие с другими виджетами.
Метод place
также имеет опцию относительной позиции, то есть,
labelD.place(relx=0.5, rely=0.5)
Где relx
и rely
находятся в диапазоне 0.0~1.0
. Это относительный процент положения виджета к размеру окна.
Например, relx=0.5, rely=0.5
означает, что виджет размещается в 50% от ширины окна и 50% от высоты окна.
relx=1.0
- правая граница окна, а rely=1.0
- нижняя граница окна.