Метод place
В конце курса рассмотрим третий и последний менеджер геометрии библиотеки tk – Place, который размещает виджеты по координатам. В tkinter использование данного управляющего размещением реализуется через метод place виджетов.
Методом place виджету указывается его положение либо в абсолютных значениях (в пикселях), либо в долях родительского окна, то есть относительно. Также абсолютно и относительно можно задавать размер самого виджета.
Основными параметрами place являются:
- anchor (якорь) – определяет часть виджета, для которой задаются координаты. Принимает значения N, NE, E, SE, SW, W, NW или CENTER. По умолчанию NW (верхний левый угол).
- relwidth , relheight (относительные ширина и высота) – определяют размер виджета в долях его родителя.
- relx , rely – определяют относительную позицию в родительском виджете. Координата (0; 0) – у левого верхнего угла, (1; 1) – у правого нижнего.
- width , height – абсолютный размер виджета в пикселях. Значения по умолчанию (когда данные опции опущены) приравниваются к естественному размеру виджета, то есть к тому, который определяется при его создании и конфигурировании.
- x , y – абсолютная позиция в пикселях. Значения по умолчанию приравниваются к нулю.
Схема с указанием относительных координат:

Для лучшего понимания разницы между абсолютным и относительным позиционированием рассмотрим пример:
from tkinter import * root = Tk() root.geometry('150x150') Button(bg='red').place(x=75, y=20) Button(bg='green').place(relx=0.3, rely=0.5) root.mainloop()

Кнопка, позиция которой была жестко задана, не изменяет своего положения, когда окно раздвигается. Кнопка с относительными координатами смещается. Опции relx и rely для нее по-прежнему 0.3 и 0.5, но уже относительно нового размера окна.
То же самое с размерами виджетов. Если они относительны, то с изменением размера родительского виджета, их размеры также будут изменяться. Если требуется, чтобы виджет всегда сохранял свой размер, последний должен указываться как абсолютный. Или не указываться вовсе, тогда будет приравнен к естественному.
… Label(bg='white').place(x=10, y=10, width=50, height=30) Label(bg='green').place(x=10, y=50, relwidth=0.3, relheight=0.15) …

Комбинируя различные варианты позиционирования и установки размеров, можно добиться интересных эффектов, а также неожиданных спецэффектов. Поэтому методом place следует пользоваться с осторожностью, хорошо понимая, что вы делаете.
Если размер окна не меняется, а интерфейс сложен, то вероятно управляющий размещением Place может быть лучшим выбором, так как с его помощью можно выполнить тонкую настройку и создать наиболее аккуратный интерфейс.
Практическая работа
За рамками данного курса было оставлено несколько классов пакета tkinter . Среди них PhotoImage , позволяющий использовать в программе внешние изображения форматов GIF и PGM. Экземпляры PhotoImage можно размещать на различных виджетах через опцию image .
… img = PhotoImage(file='smile.gif') l=Label(image=img) …
Напишите программу, состоящую из главного окна и кнопки, на которой изображен смайлик. При клике на кнопку она должна оказываться в новом случайном месте окна. Размер окна может меняться.
Курс с примерами решений практических работ: pdf-версия
X Скрыть Наверх
Tkinter. Программирование GUI на Python
Tkinter, раскрытие потенциала. + Игра на рабочем столе
Tkinter — это та библиотека, с которой на начальных этапах изучения языка python знакомились все, но обходили стороной по разным причинам. Сейчас я предлагаю вернуться назад, немного поностальгировать и открыть для себя в разы больше фич библиотеки.
ВАЖНО! Tkinter — не лучшее решение для создания больших приложений. И по большей части эта статья нацелена на начинающих программистов, которые уже имеют представление о библиотеке и хотят рыть дальше.
Улучшаем кнопки tkinter.Button
Пройдёмся по параметры кнопок, которые нам пригодятся:
- bg — фон кнопки (background color)
- fg — цвет текста кнопки (foreground color)
- bd — ширина обводи
- text — сам текст
- command — функция исполняющаяся при нажатии
- font — шрифт
- relief — стиль обводки (tk.GROOVE , tk.SUNKEN , tk.RAISED , tk.RIDGE , tk.FLAT)
- state — состояние кнопки (tk.ACTIVE , tk.DISABLED)
- underline — подчёркнутый символ текста (>-1)
- padx , pady — отступы по горизонтали , вертикали
- width , height — ширина , высота (!В СТРОЧКАХ)
- activebackground — фон кнопки при активации
- activeforeground — цвет текста кнопки при активации
- cursor — курсор (https://docs.huihoo.com/tkinter/tkinter-reference-a-gui-for-python/cursors.html)
Предлагаю сделать «кнопку ссылку», которая при нажатии будет перекидывать нас на какой-нибудь сайт. Библиотека webbrowser — встроенная, её не нужно устанавливать.
import tkinter as tk import webbrowser FORM = tk.Tk() # Создаём окно FORM .geometry('500x500') # Задаём размер def link(e = None): # !ОБРАТИТЕ ВНИМАНИЕ на e = None webbrowser.open('https://www.youtube.com/watch?v=dQw4w9WgXcQ') # Открываем браузер button = tk.Button(FORM,command = link,padx = 5,pady = 5,text = 'Link',bd = 0, fg = '#fff', bg = '#08f',underline = 0 , activebackground = '#fff', activeforeground = '#fff',cursor = 'hand2') # Инициализация кнопки button.pack(expand = 1) # Размещение кнопки по центру окна # Сюда мы ещё добавим код FORM.mainloop()

Выглядит уже неплохо. Предлагаю добавить смену цвета кнопки при наведении курсором мыши.
def focus_in(e = None): button.configure(fg = '#08f') # Задаём кнопке нужные цвета button.configure(bg = '#fff') def focus_out(e = None): button.configure(bg = '#08f') button.configure(fg = '#fff') button.bind('', focus_in) # При входе курсора в область кнопки выполняем focus_in button.bind('', focus_out) # При выходе курсора из области кнопки выполняем focus_out_out

Улучшаем окно программы
Начнём с добавления переключения на полноэкранного режима (верхней панели окна не видно) по клавише F11:
def fullscreen(e = None): if FORM.attributes('-fullscreen'): # Проверяем режим окна FORM.attributes('-fullscreen',False) # Меняем режим окна else: FORM.attributes('-fullscreen',True) # Меняем режим окна FORM.bind('',fullscreen) # Биндим окно
Теперь нужно сделать так, что бы пользователь не мог не нажать на ту самую ссылку. Давайте сделаем выход из приложения невозможным (возможным только через диспетчер задач (ctrl+shift+esc)).
def on_close(e = None): pass # Мы просто ничего не делаем # Может быть любой код # Можно так же спрашивать пользователя ВЫ ТОЧНО ХОТИТЕ ЗАКРЫТЬ ОКНО ? FORM.protocol("WM_DELETE_WINDOW", on_close) # Перехватываем событие выхода из приложения
Реализуем ка мы также и «приоритетный» режим, окно будет отображаться поверх остальных. Здесь я рекомендую использовать библиотеку keyboard (pip install keyboard), так как bind tkintera работает только если окно находиться в фокусе. Keyboard же никак не зависит от tkintera и расположения окон.
def topmost(e = None): if FORM.attributes('-topmost'): # Проверяем режим окна FORM.attributes('-topmost',False)# Меняем режим окна else: FORM.attributes('-topmost',True)# Меняем режим окна keyboard.add_hotkey('ctrl+1',topmost) # Привязываем событие к функции
Проблема окон, которые находятся поверх всех — что бы что-то под ними увидеть, нужно их передвигать, а это иногда бывает не удобно. Да бы избежать неудобств пользователя, мы можем добавить окну 50% прозрачности. Когда пользователь наводит курсор на окно, оно становится непрозрачным.
FORM.attributes('-alpha',0.5) # Задаём изначальное значение прозрачности def form_focus_in(e = None): FORM.attributes('-alpha',1) def form_focus_out(e = None): FORM.attributes('-alpha',0.5) FORM.bind('', form_focus_in) # При входе курсора в область окна выполняем form_focus_in FORM.bind('', form_focus_out)# При входе курсора в область окна выполняем form_focus_out
Поэкспериментировав с выше показанным, я думаю, вы в скором времени зададитесь вопросом «Можно ли убрать верхнюю панель у окна ?». Да, можно, но вам придётся самостоятельно реализовывать передвижение и если хотите, изменение размеров окна. Плюсы своего окна начинаются и заканчиваются том, что вы полностью контролируете внешний вид и логику окна. Также есть огромный минус — пока окно открыто, оно не отображается в панели задач, по этому ему желательно давать приоритетный режим, что бы пользователь не потерял окно под другими.
from tkinter import * # Объявляем основные цвета BGCL = '#000000' CANCELCL = '#800000' CANCELHOVCL = '#400000' INFOCL = '#000080' INFOHOVCL = '#000040' BARCL = '#004000' # Если число больше min, возвращает minrep, если число больше max, возвращает maxrep def barrier(val,min = 0, max = None,minrep = None,maxrep = None): if minrep is None:minrep = min if maxrep is None: maxrep = max if not min is None and val < min:return minrep elif not max is None and val >max: return maxrep else:return val # Просто пустая функция def empty(*args,**kwargs):pass # Класс усовершенстованого окна class Form(Tk): def __init__(self,resizeable = True,exitfunc = empty,onresizefunc = empty): Tk.__init__(self) self['bg'] = BGCL self.resizeable = resizeable self.exitfunc = exitfunc self.onresizefunc = onresizefunc self.overrideredirect(True) # убираем у окна панельку self.wm_attributes('-topmost',True) # приоритетный режим self.bar = Frame(self,bg = BARCL) # Создаём свою панельку, как отдельный виджет self.bar.place(x = 0 ,y = 0,relwidth = 1,height = 24) self.closebtn = Button(self,bg = CANCELCL,fg = BGCL,relief = FLAT,command = self.Exit,bd=0,activebackground = BGCL) self.closebtn.place(width =24,height = 24,x = self.winfo_reqwidth()-24) self.wrapbtn = Button(self,bg = INFOCL,fg = BGCL,relief = FLAT,command = self.Wrap,bd=0,activebackground = BGCL) self.wrapbtn.place(width =24,height = 24,x = self.winfo_reqwidth()-48) # Здесь биндятся функции, передвигающие окно self.bar.bind("", self.StartMove) self.bar.bind("", self.StopMove) self.bar.bind("", self.OnMotion) # Обеспечиваем hover эффект кнопкам на нашей панельке self.closebtn.bind("",self.__closebtne) self.closebtn.bind("",self.__closebtnl) self.wrapbtn.bind("",self.__wrapbtne) self.wrapbtn.bind("",self.__wrapbtnl) # Запоминаем ширину и высоту окна self.width = self.winfo_reqwidth() self.height = self.winfo_reqheight() # В этом framе создавайте новые виджеты self.content = Frame(self,bg = BGCL,highlightthickness = 0) self.content.place(x=0,y = 24, width = self.width,height = self.height-24) if resizeable: # создаём кнопку изменения размера self.resizebtn = Button(self,bg = BARCL,fg = BGCL,relief = FLAT,bd=0,activebackground = BGCL,text = '=',font = ('Fixedsys',11),cursor = 'tcross') self.resizebtn.place(width =12,height = 12,x = self.winfo_reqwidth()-12,y = self.winfo_reqheight()-12) # Её hover эффект self.resizebtn.bind("",self.__resizebtne) self.resizebtn.bind("",self.__resizebtnl) # Здесь биндятся функции, меняющие размер окна self.resizebtn.bind("", self.StartResize) self.resizebtn.bind("", self.StopResize) self.resizebtn.bind("", self.OnResize) # Событие развёртывания окна (Редкое) self.bind('',self.Show) # функции hover эффектов def __closebtne(self,event = None): self.closebtn['bg'] = CANCELHOVCL def __closebtnl(self,event = None): self.closebtn['bg'] = CANCELCL def __resizebtne(self,event = None): self.resizebtn['bg'] = BGCL self.resizebtn['fg'] = BARCL def __resizebtnl(self,event = None): self.resizebtn['bg'] = BARCL self.resizebtn['fg'] = BGCL def __wrapbtne(self,event = None): self.wrapbtn['bg'] = INFOHOVCL def __wrapbtnl(self,event = None): self.wrapbtn['bg'] = INFOCL # Передвижение окна def StartMove(self, event = None): self.dragx = event.x self.dragy = event.y def StopMove(self, event = None): self.dragx = None self.dragy = None def OnMotion(self, event = None): deltax = event.x - self.dragx deltay = event.y - self.dragy x = self.winfo_x() + deltax y = self.winfo_y() + deltay self.geometry("+%s+%s" % (x, y)) # Изменение размера окна def StartResize(self, event = None): self.resizex = event.x self.resizey = event.y def StopResize(self, event = None): self.resizex = None self.resizey = None def OnResize(self, event = None): deltax = event.x - self.resizex deltay = event.y - self.resizey x = self.width + deltax y = self.height + deltay self.width =barrier(x,min=self.minsize()[0]) self.height = barrier(y,min=self.minsize()[1]) self.geometry("%sx%s" % (self.width,self.height)) self.Resize() # Функция вызывается после изменения размера, что бы заного разместить все кнопки. def Resize(self,event = None): # onresizefunc - вы можете передать функцию при инициализации, она будет выполнятся здесь self.onresizefunc(self.width,self.height) if self.resizeable: self.resizebtn.place_configure(x = self.width-12,y = self.height-12) self.closebtn.place_configure(y=0,x = self.width-24) self.wrapbtn.place_configure(y=0,x = self.width-48) self.content.place_configure(width = self.width,height = self.height-24) # Выполняется после нажатия красной кнопки def Exit(self,event = None): # exitfunc - вы можете передать функцию при инициализации, она будет выполнятся здесь self.exitfunc() self.destroy() # Сворачивает окно def Wrap(self,event = None): self.withdraw() # скрытие окна self.overrideredirect(False) # возвращаем ему панельку self.wm_state('iconic') # сворачиваем def Show(self,event = None): # Окно уже развёрнуто self.overrideredirect(True) #Просто обратно забираем панельку FORM = Form() # Создаём объект Form (изменённый Tk) FORM.minsize(200,200) #Задаём минимальный размер FORM.mainloop()
Вкратце опишу произошедшее выше. Мы создаём класс Form на основе класса Tk, то есть Form это модифицированный Tk. При инициализации объекта мы добавляем ему кнопки закрытия, сворачивания, изменения размера и два фрейма, панелька и контент. Делаем ховер эффект для каждой кнопки. Дальше реализуем перемещение окна. По нажатию на клавишу мыши координаты сохраняются, затем по мере движения мыши в соответствии с сохранёнными координатами меняется положение окна. С изменениями размера система та же, но при изменениях размера меняется также положение кнопок и. т. п.

Необычная игра
Скептик скажет «Питон не для игр, а tkinter так уж тем более». И я с этим скептиком от части согласен, tkinter НЕ для игр, для игр лучше pygame, а вот для «десктопных» игр это самое простое и единственное мне известное решение. Под «десктопной» игрой я подразумеваю игру, которая отрисовывается поверх всех окон, прямо на рабочем столе. В этом примере пиксельный человечек прыгает по окнам, это просто пример.
Как работает отрисовка поверх экрана в tkinter? Создаётся полноэкранное белое окно, на нём создаётся белый canvas, на canvase отрисовывается графика и всё белое заменяется прозрачным. Цвет не обязательно должен быть белым. В подобных играх также следует использовать keyboard, а именно функцию is_pressed() для проверки нажатия клавиш.
import tkinter as tk import keyboard FORM = tk.Tk() def Update(e = None): # Ваш игровой цикл FORM.after(int(1000/FPS),Update) FPS = 60 CANVAS = tk.Canvas(FORM,bg = 'white',bd = 0,highlightthickness = 0) CANVAS.place(x=0,y=0,width = FORM.winfo_screenwidth(),height = FORM.winfo_screenheight()) FORM.overrideredirect(True) FORM.state('zoomed') FORM.wm_attributes("-topmost", True) FORM.wm_attributes("-transparentcolor", "white") FORM.after(int(1000/FPS),Update) FORM.mainloop()
Я также напишу статью про создание «десктопной» игры в скором времени.
9. Tkinter. Позиционирование элементов¶
Метод place() позволяет более точно настроить параметры позиционирования. Он принимает следующие параметры:
- height и width: устанавливают соответственно высоту и ширину элемента в пикселях
- relheight и relwidth: также задают соответственно высоту и ширину элемента, но в качестве значения используется число float в промежутке между 0.0 и 1.0, которое указывает на долю от высоты и ширины родительского контейнера
- x и y: устанавливают смещение элемента по горизонтали и вертикали в пикселях соответственно относительно верхнего левого угла контейнера
- relx и rely: также задают смещение элемента по горизонтали и вертикали, но в качестве значения используется число float в промежутке между 0.0 и 1.0, которое указывает на долю от высоты и ширины родительского контейнера
- bordermode: задает формат границы элемента. Может принимать значение INSIDE (по умолчанию) и OUTSIDE
- anchor: устанавливает опции растяжения элемента. Может принимать значения n, e, s, w, ne, nw, se, sw, c, которые являются сокращениями от Noth(север — вверх), South (юг — низ), East (восток — правая сторона), West (запад — левая сторона) и Center (по центру). Например, значение nw указывает на верхний левый угол
Например, разместим кнопку с шириной 130 пикселей и высотой 30 пикселей в центре окна:
from tkinter import * clicks = 0 def click_button(): global clicks clicks += 1 btn.config(text="Clicks <>".format(clicks)) root = Tk() root.title("GUI на Python") root.geometry("300x250") btn = Button(text="Clicks 0", background="#555", foreground="#ccc", padx="20", pady="8", font="16", command=click_button) btn.place(relx=.5, rely=.5, anchor="c", height=30, width=130, bordermode=OUTSIDE) root.mainloop()

Следует заметить, что при использовании метода place() не надо использовать метод pack(), чтобы сделать элемент видимым.
Или разместим три кнопки:
from tkinter import * root = Tk() root.title("GUI на Python") root.geometry("300x250") btn1 = Button(text="x=10, y=20", background="#555", foreground="#ccc", padx="14", pady="7", font="13") btn1.place(x=10, y=20) btn2 = Button(text="x=50, y=100", background="#555", foreground="#ccc", padx="14", pady="7", font="13") btn2.place(x=50, y=100) btn3 = Button(text="x=140, y=160", background="#555", foreground="#ccc", padx="14", pady="7", font="13") btn3.place(x=140, y=160) root.mainloop()

9.2. Метод grid()¶
Метод grid применяет другой подход к позиционированию элементов, нежели метод place, позволяя поместить элемент в определенную ячейку условной сетки или грида.
Метод grid применяет следующие параметры:
- column: номер столбца, отсчет начинается с нуля
- row: номер строки, отсчет начинается с нуля
- columnspan: сколько столбцов должен занимать элемент
- rowspan: сколько строк должен занимать элемент
- ipadx и ipady: отступы по горизонтали и вертикали соответственно от границ элемента до его текста
- padx и pady: отступы по горизонтали и вертикали соответственно от границ ячейки грида до границ элемента
- sticky: выравнивание элемента в ячейке, если ячейка больше элемента. Может принимать значения n, e, s, w, ne, nw, se, sw, которые указывают соответствующее направление выравнивания
Начальный пример демонстрации позиционирования с помощью сетки:
from tkinter import * window = Tk() window.title("Welcome to grid app!") window.geometry('350x200') lbl = Label(window, text="Hello!") btn = Button(window, text="Click Me!") lbl.grid(column=0, row=0) btn.grid(column=1, row=0) window.mainloop()

Использу следующий пример можно понять как расположить элементы на сетке вида шахматной доски:
from tkinter import * window = Tk() window.title("Welcome to grid app!") lbl = Label(window, text="Hello!") btn1 = Button(window, text="Click Me!") btn2 = Button(window, text="Click Me!") btn3 = Button(window, text="Click Me!") btn1.grid(column=0, row=0) lbl.grid(column=1, row=0) btn2.grid(column=2, row=0) btn3.grid(column=1, row=1) window.mainloop()

Пример окна для ввода логина и пароля:
from tkinter import * root = Tk() root.title("Welcome to the second entry app") lbl_login = Label(root, text="Login") lbl_pass = Label(root, text="Password") txt1 = Entry(root, width=10) txt2 = Entry(root, width=10) btn = Button(root, text="Enter") lbl_login.grid(row=0, sticky=E) lbl_pass.grid(row=1, sticky=E) txt1.grid(row=0, column=1) txt2.grid(row=1, column=1) btn.grid(columnspan=2, sticky=NSEW) root.mainloop()
Структура приложения и работа с кнопкам / tkinter 1
Одно из главных преимуществ создания приложения с Tkinter в том, что с его помощью очень просто настроить интерфейс всего в несколько строк. И если программа становится сложнее, то и сложнее логически разделять ее на части, а организованная структура помогает сохранять код в чистом виде.
Простой пример
Возьмем в качестве примера следующую программу:
from tkinter import * root = Tk()
btn = Button(root, text="Нажми!")
btn.config(command=lambda: print("Привет, Tkinter!"))
btn.pack(padx=120, pady=30)
root.title("Мое приложение Tkinter")
root.mainloop()Она создает окно с кнопкой, которая выводит Привет, Tkinter! каждый раз при нажатии. Кнопка расположена с внутренним отступом 120px по горизонтальной оси и 30px – по вертикальной. Последняя строка запускает основной цикл, который обрабатывает все пользовательские события и обновляет интерфейс до закрытия основного окна.
Программу можно запустить, чтобы убедиться, что она работает. Все переменные определяются в глобальном пространстве имен, и чем больше виджетов добавляется, тем сложнее разобраться в том, какие части они используют.
Wildcard-импорты ( from … import * ) считаются плохой практикой, поскольку они загрязняют глобальное пространство имен. Здесь они используются для иллюстрации анти-паттерна, который часто встречается в примерах онлайн.
Эти проблемы настройки решаются с помощью базовых техник объектно-ориентированного программирования, что считается хорошей практикой для любых типов программ на Python.
Правильный пример
Чтобы улучшить модуль простой программы, стоит определить несколько классов, которые станут обертками вокруг глобальных переменных:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.btn = tk.Button(self, text="Нажми!",
command=self.say_hello)
self.btn.pack(padx=120, pady=30)
def say_hello(self):
print("Привет, Tkinter!")
if __name__ == "__main__":
app = App()
app.title("Мое приложение Tkinter")
app.mainloop()Теперь каждая переменная хранится в конкретной области видимости, включая функцию command , которая находится в отдельном методе.
Как работает это приложение?
Во-первых нужно заменить wildcard-импорт на импорт в формате import … as для лучшего контроля над глобальным пространством имен.
Затем класс App определяется как подкласс Tk , который теперь ссылается на пространство имен tk . Для правильной инициализации базового класса, вызывается метод __init__() класса Tk с помощью встроенной функции super() . За это отвечают следующие строки:
class App(tk.Tk):
def __init__(self):
super().__init__()
# .Теперь есть ссылка на экземпляр App с переменной self . Так что виджет кнопки будет добавлен как атрибут класса.
Это может казаться излишним для такой простой программы, но подобный рефакторинг помогает работать с каждой отдельной частью. Создание кнопки отделено от обратного вызова, которые исполняется при нажатии. А генерация приложения перемещена в if __name__ == "main" , что является стандартной практикой для исполняемых скриптов в Python.
Такой же принцип будет использовать в примерах и дальше, поэтому его можно взять как шаблон-стартовая точка для крупных приложений.
Дополнение о структуре приложения
Класс Tk вынесен в отдельный класс в примере, но распространенной практикой считается выделять так же другие классы виджетов. Это делается для воссоздания тех же инструкций, которые были до рефакторинга.
Однако может быть более удобно разделять классы Frame или Toplevel особенно для больших программ, где, например, есть несколько окон. Это все потому что у приложения Tkinter должен быть один экземпляр Tk , а система создает их автоматически при создании экземпляра виджета до создания экземпляра самого Tk .
Помните, что это не влияет на структуру класса App , поскольку у всех классов виджетов есть метод mainloop , который запускает основной цикл Tk .
Работа с кнопками
Виджеты кнопок представляют собой кликабельные элементы графического интерфейса приложений. Они обычно используют текст или изображение, указывающие на то, какое действие будет выполнено при нажатии. Tkinter позволяет легко настраивать их функциональность с помощью стандартных настроек класса виджета Button .
Как создать кнопку
Следующий блок содержит кнопку с изображением, которая выключается при нажатии, а также список кнопок с разными типами анимации после нажатия:
import tkinter as tk
RELIEFS = [tk.SUNKEN, tk.RAISED, tk.GROOVE, tk.RIDGE, tk.FLAT]
class ButtonsApp(tk.Tk):
def __init__(self):
super().__init__()
self.img = tk.PhotoImage(file="python.gif")
self.btn = tk.Button(self, text="Кнопка с изображением",
image=self.img, compound=tk.LEFT,
command=self.disable_btn)
self.btns = [self.create_btn(r) for r in RELIEFS]
self.btn.pack()
for btn in self.btns:
btn.pack(padx=10, pady=10, side=tk.LEFT)def create_btn(self, relief):
return tk.Button(self, text=relief, relief=relief)def disable_btn(self):
self.btn.config(state=tk.DISABLED)if __name__ == "__main__":
app = ButtonsApp()
app.mainloop()Цель программы — показать разные варианты настройки, которые могут быть использованы при создании виджета кнопки.
После выполнения кода выше, возвращается следующее:
Простейший способ создания экземпляра Button — использование параметра text для настройки метки кнопки и command , который ссылается на вызываемую функцию при нажатии кнопки.
В этом примере также добавляется PhotoImage с помощью параметра image , который имеет приоритет над строкой text . Этот параметр используется для объединения изображения и текста на одной кнопке, определяя местоположение, где будет находиться картинка. Он принимает следующие константы: CENTER, BOTTOM, LEFT, RIGHT и TOP.
Второй ряд кнопок создается с помощью сгенерированного списка и списка значений RELIEF . Метка каждой кнопки соответствует константе, так что можно заметить разницу во внешнем виде.
Для сохранения ссылки на экземпляр PhotoImage использовался атрибут, хотя его и нет вне метода __init__ . Причина в том, что изображения удаляются при сборке мусора. Это и происходит, если объявить их в качестве локальных переменных.
Для избежания этого нужно помнить о сохранении ссылки на каждый объект PhotoImage до тех пор, пока окно, где он показывается, не закрыто.
Следующий урок: Работа с текстом (в разработке)

