Разметки pack, grid и place для позиционирования в Tkinter

В данном уроке по изучению Tkinter мы познакомимся с менеджерами разметки. Когда мы создаем графический интерфейс нашего приложения, мы определяем, какие виджеты будем использовать, и как они будут расположены в приложении. Для того, чтобы организовать виджеты в приложении, используются специальные невидимые объекты – менеджеры разметки.

Содержание курса

  1. Создание окна по центру и кнопка выхода в Tkinter
  2. Разметка виджетов в Tkinter — pack, grid и place
  3. Виджеты Checkbutton, Label, Scale и Listbox в Tkinter
  4. Меню, подменю и панель инструментов в Tkinter
  5. Диалоговые окна в Tkinter
  6. Рисуем линии, прямоугольники, круг и текст в Tkinter
  7. Пишем игру змейка на Tkinter

Содержание статьи

Существует два вида виджетов:

  • контейнеры;
  • дочерние виджеты.

Контейнеры объединяют виджеты для формирования разметки. У Tkinter есть три встроенных менеджера разметки: pack, grid и place.

  • Place – это менеджер геометрии, который размещает виджеты, используя абсолютное позиционирование.
  • Pack – это менеджер геометрии, который размещает виджеты по горизонтали и вертикали.
  • Grid – это менеджер геометрии, который размещает виджеты в двухмерной сетке.

В большинстве случаев разработчикам необходимо использовать менеджеры разметки. Есть несколько ситуаций, в которых следует использовать именно абсолютное позиционирование. В рамках абсолютного позиционирования разработчик определяет позицию и размер каждого виджета в пикселях. Во время изменения размеров окна размер и позиция виджетов не меняются.

Изображения из примера:

Сохраните их в папке рядом с файлом absolute.py код для которого будет ниже.

Таким образом, на разных платформах приложения выглядят по-разному. То, что выглядит нормально на Linux, может отображаться некорректно на Mac OS. Изменение шрифтов в нашем приложении также может испортить разметку. Если мы переведем наше приложение на другой язык, мы должны доработать и разметку.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

from PIL import Image, ImageTk

from tkinter import Tk, BOTH

from tkinter.ttk import Frame, Label, Style

class Example(Frame):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):

        self.master.title("Absolute positioning")

        self.pack(fill=BOTH, expand=1)

        Style().configure("TFrame", background="#333")

        bard = Image.open("bardejov.jpg")

        bardejov = ImageTk.PhotoImage(bard)

        label1 = Label(self, image=bardejov)

        label1.image = bardejov

        label1.place(x=20, y=20)

        rot = Image.open("rotunda.jpg")

        rotunda = ImageTk.PhotoImage(rot)

        label2 = Label(self, image=rotunda)

        label2.image = rotunda

        label2.place(x=40, y=160)

        minc = Image.open("mincol.jpg")

        mincol = ImageTk.PhotoImage(minc)

        label3 = Label(self, image=mincol)

        label3.image = mincol

        label3.place(x=170, y=50)

def main():

    root = Tk()

    root.geometry("300x280+300+300")

    app = Example()

    root.mainloop()

if __name__ == '__main__':

    main()

В этом примере мы расположили три изображения при помощи абсолютного позиционирования. Мы использовали менеджер геометрии place.

from PIL import Image, ImageTk

Мы использовали Image и ImageTk из модуля PIL (Python Imaging Library).

style = Style()

style.configure("TFrame", background="#333")

При помощи стилей, мы изменили фон нашего окна на темно-серый.

bard = Image.open("bardejov.jpg")

bardejov = ImageTk.PhotoImage(bard)

Мы создали объект изображения и объект фото изображения из сохраненных ранее изображений в текущей рабочей директории.

label1 = Label(self, image=bardejov)

Мы создали Label (ярлык) с изображением. Данные ярлыки могут содержать как изображения, так и текст.

Нам нужно сохранить ссылку на изображение, чтобы не потерять его если сборщик мусора (Garbage collector) его не закроет.

Ярлык размещен в рамке по координатам x=20 и y=20.

place() Абсолютное позиционирование

Tkinter pack() — размещение виджетов по горизонтали и вертикали

Менеджер геометрии pack() упорядочивает виджеты в горизонтальные и вертикальные блоки. Макетом можно управлять с помощью параметров fill, expand и side.

Пример создания кнопок в Tkinter

В следующем примере мы разместим две кнопки в нижнем правом углу нашего окна. Для этого мы воспользуемся менеджером pack.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

from tkinter import Tk, RIGHT, BOTH, RAISED

from tkinter.ttk import Frame, Button, Style

class Example(Frame):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):

        self.master.title("Кнопки в kinter")

        self.style = Style()

        self.style.theme_use("default")

        frame = Frame(self, relief=RAISED, borderwidth=1)

        frame.pack(fill=BOTH, expand=True)

        self.pack(fill=BOTH, expand=True)

        closeButton = Button(self, text="Закрыть")

        closeButton.pack(side=RIGHT, padx=5, pady=5)

        okButton = Button(self, text="Готово")

        okButton.pack(side=RIGHT)

def main():

    root = Tk()

    root.geometry("300x200+300+300")

    app = Example()

    root.mainloop()

if __name__ == '__main__':

    main()

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

У нас есть две рамки. Первая рамка – основная, а также вторая – дополнительная, которая растягивается в обе стороны и сдвигает две кнопки в нижнюю часть основной рамки. Кнопки находятся в горизонтальном контейнере и размещены в ее правой части.

frame = Frame(self, relief=RAISED, borderwidth=1)

frame.pack(fill=BOTH, expand=True)

Мы создали еще один виджет Frame. Этот виджет занимает практически все пространство окна. Мы изменяем границы рамки, чтобы сама рамка была видна. По умолчанию она плоская.

closeButton = Button(self, text="Закрыть")

closeButton.pack(side=RIGHT, padx=5, pady=5)

Кнопка closeButton создана. Она расположена в горизонтальном контейнере. Параметр side позволяет поместить кнопку в правой части горизонтальной полосы. Параметры padx и pady позволяют установить отступ между виджетами. Параметр padx устанавливает пространство между виджетами кнопки closeButton и правой границей корневого окна.

okButton.pack(side=RIGHT)

Кнопка okButton размещена возле closeButton с установленным отступом (padding) в 5 пикселей.

pack() - размещение виджетов по горизонтали и вертикали

Создаем приложение для отзывов на Tkinter

Менеджер pack – это простой менеджер разметки. Его можно использовать для простых задач разметки. Чтобы создать более сложную разметку, необходимо использовать больше рамок, каждая из которых имеет собственный менеджер разметки.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

from tkinter import Tk, Text, BOTH, X, N, LEFT

from tkinter.ttk import Frame, Label, Entry

class Example(Frame):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):

        self.master.title("Оставить отзыв")

        self.pack(fill=BOTH, expand=True)

        frame1 = Frame(self)

        frame1.pack(fill=X)

        lbl1 = Label(frame1, text="Заголовок", width=10)

        lbl1.pack(side=LEFT, padx=5, pady=5)

        entry1 = Entry(frame1)

        entry1.pack(fill=X, padx=5, expand=True)

        frame2 = Frame(self)

        frame2.pack(fill=X)

        lbl2 = Label(frame2, text="Автор", width=10)

        lbl2.pack(side=LEFT, padx=5, pady=5)

        entry2 = Entry(frame2)

        entry2.pack(fill=X, padx=5, expand=True)

        frame3 = Frame(self)

        frame3.pack(fill=BOTH, expand=True)

        lbl3 = Label(frame3, text="Отзыв", width=10)

        lbl3.pack(side=LEFT, anchor=N, padx=5, pady=5)

        txt = Text(frame3)

        txt.pack(fill=BOTH, pady=5, padx=5, expand=True)

def main():

    root = Tk()

    root.geometry("300x300+300+300")

    app = Example()

    root.mainloop()

if __name__ == '__main__':

    main()

На этом примере видно, как можно создать более сложную разметку с многочисленными рамками и менеджерами pack().

self.pack(fill=BOTH, expand=True)

Первая рамка является базовой. На ней располагаются все остальные рамки. Стоит отметить, что даже при организации дочерних виджетов в рамках, мы управляем ими на базовой рамке.

frame1 = Frame(self)

frame1.pack(fill=X)

lbl1 = Label(frame1, text="Заголовок", width=10)

lbl1.pack(side=LEFT, padx=5, pady=5)

entry1 = Entry(frame1)

entry1.pack(fill=X, padx=5, expand=True)

Первые два виджета размещены на первой рамке. Поле для ввода данных растянуто горизонтально с параметрами fill и expand.

frame3 = Frame(self)

frame3.pack(fill=BOTH, expand=True)

lbl3 = Label(frame3, text="Отзыв", width=10)

lbl3.pack(side=LEFT, anchor=N, padx=5, pady=5)        

txt = Text(frame3)

txt.pack(fill=BOTH, pady=5, padx=5, expand=True)

В третьей рамке мы разместили ярлык и виджет для ввода текста. Ярлык закреплен по северной стороне anchor=N, а виджет текста занимает все остальное пространство.

приложение для отзывов на Tkinter

Разметка grid() в Tkinter для создания калькулятора

Менеджер геометрии grid() в Tkinter используется для создания сетки кнопок для калькулятора.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

from tkinter import Tk, W, E

from tkinter.ttk import Frame, Button, Entry, Style

class Example(Frame):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):

        self.master.title("Калькулятор на Tkinter")

        Style().configure("TButton", padding=(0, 5, 0, 5), font='serif 10')

        self.columnconfigure(0, pad=3)

        self.columnconfigure(1, pad=3)

        self.columnconfigure(2, pad=3)

        self.columnconfigure(3, pad=3)

        self.rowconfigure(0, pad=3)

        self.rowconfigure(1, pad=3)

        self.rowconfigure(2, pad=3)

        self.rowconfigure(3, pad=3)

        self.rowconfigure(4, pad=3)

        entry = Entry(self)

        entry.grid(row=0, columnspan=4, sticky=W+E)

        cls = Button(self, text="Очистить")

        cls.grid(row=1, column=0)

        bck = Button(self, text="Удалить")

        bck.grid(row=1, column=1)

        lbl = Button(self)

        lbl.grid(row=1, column=2)

        clo = Button(self, text="Закрыть")

        clo.grid(row=1, column=3)

        sev = Button(self, text="7")

        sev.grid(row=2, column=0)

        eig = Button(self, text="8")

        eig.grid(row=2, column=1)

        nin = Button(self, text="9")

        nin.grid(row=2, column=2)

        div = Button(self, text="/")

        div.grid(row=2, column=3)

        fou = Button(self, text="4")

        fou.grid(row=3, column=0)

        fiv = Button(self, text="5")

        fiv.grid(row=3, column=1)

        six = Button(self, text="6")

        six.grid(row=3, column=2)

        mul = Button(self, text="*")

        mul.grid(row=3, column=3)

        one = Button(self, text="1")

        one.grid(row=4, column=0)

        two = Button(self, text="2")

        two.grid(row=4, column=1)

        thr = Button(self, text="3")

        thr.grid(row=4, column=2)

        mns = Button(self, text="-")

        mns.grid(row=4, column=3)

        zer = Button(self, text="0")

        zer.grid(row=5, column=0)

        dot = Button(self, text=".")

        dot.grid(row=5, column=1)

        equ = Button(self, text="=")

        equ.grid(row=5, column=2)

        pls = Button(self, text="+")

        pls.grid(row=5, column=3)

        self.pack()

def main():

    root = Tk()

    app = Example()

    root.mainloop()

if __name__ == '__main__':

    main()

Менеджер grid() используется для организации кнопок в контейнере рамки.

Style().configure("TButton", padding=(0, 5, 0, 5),

    font='serif 10')

Мы настроили виджет кнопки так, чтобы отображался специфический шрифт и применялся отступ (padding) в 3 пикселя.

self.columnconfigure(0, pad=3)

...        

self.rowconfigure(0, pad=3)

Мы использовали методы columnconfigure() и rowconfigure() чтобы создать определенное пространство в сетке строк и столбцов. Благодаря этому шагу мы разделяем кнопки определенным пустым пространством.

entry = Entry(self)

entry.grid(row=0, columnspan=4, sticky=W+E)

Виджет графы ввода – это место, где будут отображаться цифры. Данный виджет расположен в первом ряду и охватывает все четыре столбца. Виджеты могут не занимать все пространство, которое выделяется клетками в созданной сетке.

Параметр sticky расширяет виджет в указанном направлении. В нашем случае, мы можем убедиться, что наш виджет графы ввода был расширен слева направо W+E (восток-запад).

cls = Button(self, text="Очистить")

cls.grid(row=1, column=0)

Кнопка очистки установлена во второй строке и первом столбце. Стоит отметить, что строки и столбцы начинаются с нуля.

Метод pack() показывает виджет рамки и дает ей первоначальный размер. Если дополнительные параметры не указываются, размер будет таким, чтобы все дочерние виджеты могли поместиться. Этот метод компонует виджет рамки в верхнем корневом окне, которое также является контейнером. Менеджер grid() используется для организации кнопок в виджете рамки.

Создание калькулятора на Tkinter

Пример создания диалогового окна в Tkinter

Следующий пример создает диалоговое окно, используя менеджер геометрии grid.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

from tkinter import Tk, Text, BOTH, W, N, E, S

from tkinter.ttk import Frame, Button, Label, Style

class Example(Frame):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):

        self.master.title("Диалоговое окно в Tkinter")

        self.pack(fill=BOTH, expand=True)

        self.columnconfigure(1, weight=1)

        self.columnconfigure(3, pad=7)

        self.rowconfigure(3, weight=1)

        self.rowconfigure(5, pad=7)

        lbl = Label(self, text="Окна")

        lbl.grid(sticky=W, pady=4, padx=5)

        area = Text(self)

        area.grid(row=1, column=0, columnspan=2, rowspan=4, padx=5, sticky=E+W+S+N)

        abtn = Button(self, text="Активир.")

        abtn.grid(row=1, column=3)

        cbtn = Button(self, text="Закрыть")

        cbtn.grid(row=2, column=3, pady=4)

        hbtn = Button(self, text="Помощь")

        hbtn.grid(row=5, column=0, padx=5)

        obtn = Button(self, text="Готово")

        obtn.grid(row=5, column=3)

def main():

    root = Tk()

    root.geometry("350x300+300+300")

    app = Example()

    root.mainloop()

if __name__ == '__main__':

    main()

В этом примере мы использовали виджет ярлыкатекстовой виджет и четыре кнопки.

self.columnconfigure(1, weight=1)

self.columnconfigure(3, pad=7)

self.rowconfigure(3, weight=1)

self.rowconfigure(5, pad=7)

Мы добавили небольшое пространство между виджетами в сетке. Параметр weight создает возможность расширения второго столбца и четвертого ряда. В этом ряду и столбце находится текстовой виджет, поэтому оставшееся пространство заполняет данный виджет.

lbl = Label(self, text="Окна")

lbl.grid(sticky=W, pady=4, padx=5)

Виджет ярлыка также создается и помещается в сетку. Если не указываются ряд и столбец, тогда он займет первый ряд и столбец. Ярлык закрепляется у западной части окна sticky=W и имеет определенные отступы вокруг своих границ.

area = Text(self)

area.grid(row=1, column=0, columnspan=2, rowspan=4,

    padx=5, sticky=E+W+S+N)

Создается текстовый виджет и помещается во второй ряд и первый столбец. Он охватывает два столбца и четыре строки.

Между виджетом и левым краем корневого окна присутствует пространство в 4 пикселя. Также, виджет закреплен около всех четырех сторон. Поэтому, когда окно расширяется, виджеты текстов увеличиваются во всех направлениях.

abtn = Button(self, text="Активир.")

abtn.grid(row=1, column=3)

cbtn = Button(self, text="Закрыть")

cbtn.grid(row=2, column=3, pady=4)

Эти две кнопки находятся возле текстового виджета.

hbtn = Button(self, text="Помощь")

hbtn.grid(row=5, column=0, padx=5)

obtn = Button(self, text="Готово")

obtn.grid(row=5, column=3)

Эти две кнопки находятся под текстовым виджетом. Кнопка «Помощь» расположена в первом столбце, а кнопка «Готово» в последнем столбце.
В этой части изучения Tkinter мы рассказали о работе с разметкой виджетов.

Создание диалогового окна в Tkinter

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.

E-mail: vasile.buldumac@ati.utm.md

Образование
Universitatea Tehnică a Moldovei (utm.md)

  • 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
  • 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»