Работа мечты в один клик 💼

💭Мечтаешь работать в Сбере, но не хочешь проходить десять кругов HR-собеседований? Теперь это проще, чем когда-либо!
💡AI-интервью за 15 минут – и ты уже на шаг ближе к своей новой работе.
Как получить оффер? 📌 Зарегистрируйся 📌 Пройди AI-интервью 📌 Получи обратную связь сразу же!
HR больше не тянут время – рекрутеры свяжутся с тобой в течение двух дней! 🚀
Реклама. ПАО СБЕРБАНК, ИНН 7707083893. Erid 2VtzquscAwp
Графический интерфейс для программы на Python можно создать с помощью одной из специальных GUI библиотек:
- Tkinter
- wxPython
- PyQt
- PySide
- Kivy
- PyGTK
У каждой из этих библиотек есть свои преимущества и недостатки. Только одна из них, Tkinter, входит в стандартную поставку Python. Виджеты Tkinter не отличаются сногсшибательной стильностью – это ее единственный очевидный минус. Преимуществ у Tkinter гораздо больше, чем недостатков. Эта библиотека:
- Максимально проста в изучении и использовании.
- Имеет детальную и доступную документацию.
- Помимо базовых элементов интерфейса, содержит два мощных виджета – Text (многострочное текстовое поле с поддержкой форматирования) и Canvas («холст», на котором можно рисовать и отображать любые графические объекты).
- Включает в себя модуль ttk, который предоставляет в распоряжение разработчика набор дополнительных виджетов – Combobox, Notebook, Treeview, Progressbar, Scale и другие.
- Позволяет сделать интерфейс адаптивным.
- Отлично подходит для начинающих – поэтому на ней мы и сосредоточимся.
Создание окна приложения с Tkinter
Для создания простого окна приложения в Tkinter выполните следующие действия:
- Импортируйте модуль
import tkinter
. - Создайте новый объект
Tk
, который представляет собой главное окно приложения. - (Опционально) Задайте заголовок окна с помощью метода
title()
объектаTk
. - (Опционально) Установите размер окна с помощью метода
geometry()
объекта Tk. Методgeometry()
принимает строковый параметр в формате"ширинаxвысота"
. - Вызовите метод
mainloop()
объекта Tk, чтобы запустить основной цикл GUI приложения.
Вот пример кода, который создает простое окно размером 250 на 250 пикселей с заголовком «Мое приложение»:
import tkinter as tk
# Создайте новый объект Tk
root = tk.Tk()
# Задайте заголовок окна
root.title("Мое приложение")
# Установите размер окна
root.geometry("250x250")
# Запустите основной цикл
root.mainloop()
Позиционирование окна в центре экрана
Чтобы разместить окно Tkinter приложения в центре экрана, необходимо:
- Воспользоваться методами winfo_screenwidth() и winfo_screenheight() для получения ширины и высоты экрана соответственно.
- Передать в метод geometry() координаты x и y, равные половине ширины и высоты экрана за минусом половины ширины и высоты окна приложения.
Код будет выглядеть так:
import tkinter as tk
# Создаем окно
root = tk.Tk()
# Получаем ширину и высоту экрана
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
# Вычисляем координаты окна приложения
window_width = 500
window_height = 300
x = (screen_width // 2) - (window_width // 2)
y = (screen_height // 2) - (window_height // 2)
root.geometry(f"{window_width}x{window_height}+{x}+{y}")
# Запускаем программу
root.mainloop()
Теперь окно расположено точно в центре экрана:
Размещение элементов интерфейса в Tkinter
Элементы интерфейса в Tkinter называются виджетами. Существует три основных способа расположения виджетов на поверхности окна: pack(), place() и grid(). Каждый из этих методов имеет свои преимущества и недостатки, и выбор оптимального способа зависит от конкретной ситуации.
pack() – упорядочивает виджеты по горизонтали или вертикали. Он прост в использовании, не требует дополнительных параметров (указания отступов, конкретной позиции). Подходит для создания простых интерфейсов. Недостаток – с помощью pack() проблематично реализовать сложную компоновку, например, сетку или перекрывание виджетов: для этого нужно комбинировать метод с place().
import tkinter as tk
root = tk.Tk()
label1 = tk.Label(root, text="Это пример использования pack()")
label1.pack()
button1 = tk.Button(root, text="Нажми!")
button1.pack()
root.mainloop()
place() – позволяет задать точное положение и размер каждого виджета в окне. Его используют, когда необходимо точно расположить виджеты или создать перекрывающиеся элементы интерфейса. Недостаток – при изменении размеров окна или содержимого виджетов трудно сохранить расположение элементов.
import tkinter as tk
root = tk.Tk()
label1 = tk.Label(root, text="Это пример использования place()")
label1.place(x=5, y=50)
button1 = tk.Button(root, text="Нажми кнопку")
button1.place(x=50, y=100)
root.mainloop()
grid() – упорядочивает виджеты в сетку из рядов и столбцов. Самый гибкий и мощный, позволяет создавать сложные интерфейсы, состоящие из виджетов разных размеров. Сложнее в использовании, чем pack(), поскольку требует больше кода для компоновки виджетов.
import tkinter as tk
root = tk.Tk()
root.title("Пример grid()")
root.geometry("250x250")
frame = tk.Frame(root)
frame.pack(expand=True)
label1 = tk.Label(frame, text="Имя:")
label1.grid(row=0, column=0)
entry1 = tk.Entry(frame)
entry1.grid(row=0, column=1)
label2 = tk.Label(frame, text="Email:")
label2.grid(row=1, column=0)
entry2 = tk.Entry(frame)
entry2.grid(row=1, column=1)
button1 = tk.Button(frame, text="Отправить")
button1.grid(row=2, column=1)
root.update_idletasks()
width = root.winfo_width()
height = root.winfo_height()
x = (root.winfo_screenwidth() // 2) - (width // 2)
y = (root.winfo_screenheight() // 2) - (height // 2)
root.geometry('{}x{}+{}+{}'.format(width, height, x, y))
root.mainloop()

В целом, pack() хорошо подходит для простых интерфейсов, place() – для более сложных, а grid() используют для создания сложных интерфейсов, которым нужна адаптивность, особое позиционирование или растягивание виджетов на несколько строк / столбцов.
Связывание виджетов с функциями
Чтобы при нажатии кнопки выполнялось какое-то действие, нужно связать кнопку с определенной функцией. Чаще всего для этого используются методы command() и bind(), но при необходимости к виджетам Tkinter можно привязывать выполнение анонимных и частично примененных функций. Проиллюстрируем примерами.
Метод command() используется для прямого связывания функции с нажатием кнопки:
import tkinter as tk
root = tk.Tk()
def say_hello():
print("Привет!")
button1 = tk.Button(root, text="Поздоровайся", command=say_hello)
button1.pack()
root.mainloop()

Метод bind(), по сравнению с command(), отличается большей гибкостью: его можно использовать для связывания функции с любым событием, происходящим в виджете – с нажатием кнопки, движением мыши, нажатием клавиши, изменением размера окна и так далее:
import tkinter as tk
root = tk.Tk()
def say_hello(event=None):
print("Привет от метода bind()")
button1 = tk.Button(root, text="Нажми кнопку")
button1.bind("<Button-1>", say_hello)
button1.pack()
root.mainloop()

Назначение кнопке анонимной функции:
import tkinter as tk
root = tk.Tk()
button1 = tk.Button(root, text="Нажми!", command=lambda: print("Привет от анонимной функции!"))
button1.pack()
root.mainloop()

Связывание кнопки с частично примененной функцией:
import tkinter as tk
from functools import partial
root = tk.Tk()
def say_hello(name):
print(f"Привет, {name}!")
button1 = tk.Button(root, text="Нажми эту кнопку", command=partial(say_hello, "пользователь"))
button1.pack()
root.mainloop()

Практика
Задание 1
Создайте Tkinter интерфейс для программы, которая получает от пользователя текст с помощью виджетов Entry и Button, а затем выводит полученную строку в терминале.
Ожидаемый результат:

Решение:
import tkinter as tk
root = tk.Tk()
def button_click():
input_text = entry.get()
print(f"Полученный текст: {input_text}")
entry = tk.Entry(root)
button = tk.Button(root, text="Отправить", command=button_click)
entry.pack()
button.pack()
root.mainloop()
Задание 2
Создайте интерфейс для программы, которая изменяет текст виджета Label после нажатия на кнопку.
Ожидаемый результат:

Решение:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="Измени этот текст")
label.pack()
def change_text():
label.config(text="Это новый текст")
button = tk.Button(root, text="Нажми кнопку!", command=change_text)
button.pack()
root.mainloop()
Задание 3
Создайте интерфейс для программы, которая получает от пользователя многострочный текст в виджете Text и выводит в виджетах Label количество слов и символов.
Ожидаемый результат:

import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
root.geometry("250x150")
root.title("Подсчет слов и символов")
def count_words_characters():
sentence = sentence_entry.get("1.0", "end-1c")
words = len(sentence.split())
characters = len(sentence)
words_label.config(text=f"Количество слов: {words}")
characters_label.config(text=f"Количество символов: {characters}")
sentence_entry = tk.Text(root, height=3, wrap="word")
words_label = ttk.Label(root)
characters_label = ttk.Label(root)
count_button = ttk.Button(root, text="Подсчитать", command=count_words_characters)
sentence_entry.pack()
words_label.pack()
characters_label.pack()
count_button.pack()
root.mainloop()
Задание 4
Напишите программу для оценки сервиса по шкале от 0 до 100. Используйте виджет Scale (ttk модуль).
Ожидаемый результат:

Решение:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text=f"Ваша оценка от 0 до 100")
label.pack()
def update_label(value):
label.config(text=f"Ваша оценка: {value}")
scale = tk.Scale(root, from_=0, to=100, orient="horizontal", command=update_label)
scale.pack()
root.mainloop()
Задание 5
Создайте индикатор выполнения задачи с помощью виджета Progressbar из модуля ttk. Индикатор должен обнуляться спустя 5 секунд.
Ожидаемый результат:

Решение:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
progressbar = ttk.Progressbar(root, orient="horizontal", length=200, mode="determinate")
progressbar.start()
def stop_progressbar():
if root.winfo_exists() and progressbar.winfo_exists():
progressbar.stop()
progressbar["value"] = 0
root.quit()
root.destroy()
if root.winfo_exists() and progressbar.winfo_exists():
root.after(5000, stop_progressbar)
progressbar.pack()
def exit_app():
stop_progressbar()
root.protocol("WM_DELETE_WINDOW", exit_app)
root.mainloop()
Задание 6
Создайте Tkinter интерфейс для программы заказа фруктов. Для вывода списка фруктов используйте виджет Combobox из модуля ttk.
Ожидаемый результат:

Решение:
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
root.title("Заказ")
def select_item():
selected_item = combobox.get()
selection_label.config(text=f"Выбрано: {selected_item}, 1 кг")
items = ["Яблоки", "Апельсины", "Виноград", "Персики", "Клубника"]
combobox = ttk.Combobox(root, values=items)
selection_label = ttk.Label(root)
select_button = ttk.Button(root, text="Заказать", command=select_item)
combobox.pack()
selection_label.pack()
select_button.pack()
root.mainloop()
Задание 7
Напишите GUI программу, которая позволяет пользователю выбрать цвет из палитры, и отображает его HEX-значение.
Ожидаемый результат:

Решение:
import tkinter as tk
import tkinter.colorchooser as cc
root = tk.Tk()
root.geometry("250x200")
root.title("Выбор цвета")
def choose_color():
color = cc.askcolor()[1]
color_label.config(text=f"Вы выбрали цвет {color}")
second_label.config(bg=color)
color_button = tk.Button(root, text="Выбрать цвет", command=choose_color)
color_label = tk.Label(root, text="Нажмите кнопку, чтобы выбрать цвет")
second_label = tk.Label(root, text="\t\t\t\n\t\t\t")
color_button.pack(pady=10)
color_label.pack()
second_label.pack(pady=10)
root.mainloop()
Задание 8
Напишите программу, которая использует виджеты Spinbox для получения двух чисел a и b (0 <= a <= 100, 0 <= b <= 100), а затем выводит сумму всех целых чисел в диапазоне от a до b включительно.
Ожидаемый результат:

Решение:
import tkinter as tk
import tkinter.ttk as ttk
class SumApp:
def __init__(self, root):
self.root = root
root.geometry("250x200")
self.root.title("Сумма чисел")
self.start_spinbox = ttk.Spinbox(root, from_=0, to=100, increment=1)
self.end_spinbox = ttk.Spinbox(root, from_=0, to=100, increment=1)
self.sum_label = tk.Label(root, text="")
self.calc_button = tk.Button(root, text="Вычислить сумму", command=self.calculate_sum)
self.start_spinbox.pack(pady=10)
self.end_spinbox.pack(pady=10)
self.sum_label.pack(pady=10)
self.calc_button.pack(pady=10)
def calculate_sum(self):
start = int(self.start_spinbox.get())
end = int(self.end_spinbox.get())
sum_ = sum(range(start, end+1))
self.sum_label.configure(text=f"Сумма чисел в диапазоне от {start} до {end}: {sum_}")
root = tk.Tk()
app = SumApp(root)
root.mainloop()
Задание 9
Создайте GUI интерфейс для программы-каталога фильмов, книг и мультфильмов. Используйте виджеты Notebook и Treeview для вывода объектов разного типа на отдельных вкладках. Реализуйте всплывающее окно для вывода полной информации об издании.
Ожидаемый результат:

Решение:
import tkinter as tk
from tkinter import ttk
def retrieve_details(event):
item = event.widget.focus()
values = event.widget.item(item)['values']
details = f"Информация об издании:\n\n"
for i in range(len(values)):
details += f"{event.widget['columns'][i].capitalize()}: {values[i]}\n"
popup = tk.Toplevel(root)
popup.title(event.widget.item(item)['text'])
popup.geometry("250x150")
popup_label = ttk.Label(popup, text=details)
popup_label.pack(pady=10)
close_button = ttk.Button(popup, text="Закрыть", command=popup.destroy)
close_button.pack()
root = tk.Tk()
root.title("Каталог")
root.geometry("600x300")
notebook = ttk.Notebook(root)
movies_tab = ttk.Frame(notebook)
books_tab = ttk.Frame(notebook)
animation_tab = ttk.Frame(notebook)
notebook.add(movies_tab, text="Фильмы")
notebook.add(books_tab, text="Книги")
notebook.add(animation_tab, text="Мультфильмы")
movies_desc = ttk.Label(movies_tab, text="Список фильмов")
books_desc = ttk.Label(books_tab, text="Список книг")
animation_desc = ttk.Label(animation_tab, text="Список мультфильмов")
movies_list = ttk.Treeview(movies_tab)
books_list = ttk.Treeview(books_tab)
animation_list = ttk.Treeview(animation_tab)
movies_list['columns'] = ('Жанр', 'Режиссер', 'Год')
books_list['columns'] = ('Автор', 'Издательство', 'Год')
animation_list['columns'] = ('Жанр', 'Студия', 'Рейтинг')
for tree in [movies_list, books_list, animation_list]:
for i, col in enumerate(tree['columns']):
tree.column(col, width=100, anchor='center')
tree.heading(col, text=col.capitalize())
tree.bind("<Double-1>", retrieve_details)
movies_list.insert('', 'end', text='М3ган', values=('Фантастика', 'Джерард Джонстоун', '2022'))
books_list.insert('', 'end', text='Перекрестки', values=('Джонатан Франзен', 'Corpus', '2022'))
animation_list.insert('', 'end', text='Пиноккио Гильермо Дель Торо', values=('фэнтези', 'Disney+', '8.2'))
movies_desc.pack()
movies_list.pack()
books_desc.pack()
books_list.pack()
animation_desc.pack()
animation_list.pack()
notebook.pack(fill='both', expand=True)
root.mainloop()
Задание 10
Напишите GUI калькулятор, который:
- Выполняет основные арифметические операции – сложение, вычитание, деление и умножение.
- Поддерживает операции с отрицательными числами, извлечение квадратного корня, деление с остатком и целочисленное деление.
Кроме того, программа должна поддерживать очистку ввода.
Ожидаемый результат:

Решение:
import tkinter as tk
from tkinter import ttk
from math import sqrt
class Calculator:
def __init__(self, master):
self.master = master
self.master.title("Калькулятор")
self.master.geometry("380x140")
self.number_entry = ttk.Entry(self.master, width=20)
self.number_entry.grid(row=0, column=0, columnspan=5, padx=5, pady=5)
self.button_1 = ttk.Button(self.master, text="1", command=lambda: self.button_click(1))
self.button_2 = ttk.Button(self.master, text="2", command=lambda: self.button_click(2))
self.button_3 = ttk.Button(self.master, text="3", command=lambda: self.button_click(3))
self.button_4 = ttk.Button(self.master, text="4", command=lambda: self.button_click(4))
self.button_5 = ttk.Button(self.master, text="5", command=lambda: self.button_click(5))
self.button_6 = ttk.Button(self.master, text="6", command=lambda: self.button_click(6))
self.button_7 = ttk.Button(self.master, text="7", command=lambda: self.button_click(7))
self.button_8 = ttk.Button(self.master, text="8", command=lambda: self.button_click(8))
self.button_9 = ttk.Button(self.master, text="9", command=lambda: self.button_click(9))
self.button_0 = ttk.Button(self.master, text="0", command=lambda: self.button_click(0))
self.button_clear = ttk.Button(self.master, text="C", command=self.button_clear)
self.button_add = ttk.Button(self.master, text="+", command=self.button_add)
self.button_equal = ttk.Button(self.master, text="=", command=self.button_equal)
self.button_subtract = ttk.Button(self.master, text="-", command=self.button_subtract)
self.button_multiply = ttk.Button(self.master, text="*", command=self.button_multiply)
self.button_divide = ttk.Button(self.master, text="/", command=self.button_divide)
self.button_floor_div = ttk.Button(self.master, text="//", command=self.button_floor_div)
self.button_modulus = ttk.Button(self.master, text="%", command=self.button_modulus)
self.button_sqrt = ttk.Button(self.master, text="√", command=self.button_sqrt)
self.button_neg = ttk.Button(self.master, text="+/-", command=self.button_neg)
self.button_1.grid(row=1, column=0)
self.button_2.grid(row=1, column=1)
self.button_3.grid(row=1, column=2)
self.button_add.grid(row=1, column=3)
self.button_floor_div.grid(row=1, column=4)
self.button_4.grid(row=2, column=0)
self.button_5.grid(row=2, column=1)
self.button_6.grid(row=2, column=2)
self.button_subtract.grid(row=2, column=3)
self.button_modulus.grid(row=2, column=4)
self.button_7.grid(row=3, column=0)
self.button_8.grid(row=3, column=1)
self.button_9.grid(row=3, column=2)
self.button_multiply.grid(row=3, column=3)
self.button_sqrt.grid(row=3, column=4)
self.button_clear.grid(row=4, column=0)
self.button_0.grid(row=4, column=1)
self.button_equal.grid(row=4, column=2)
self.button_divide.grid(row=4, column=3)
self.button_neg.grid(row=4, column=4)
self.f_num = 0
self.math = ""
def button_click(self, number):
current = self.number_entry.get()
self.number_entry.delete(0, tk.END)
self.number_entry.insert(0, str(current) + str(number))
def button_clear(self):
self.number_entry.delete(0, tk.END)
def button_add(self):
first_number = self.number_entry.get()
self.math = "addition"
self.f_num = int(first_number)
self.number_entry.delete(0, tk.END)
def button_equal(self):
second_number = self.number_entry.get()
self.number_entry.delete(0, tk.END)
if self.math == "addition":
self.number_entry.insert(0, self.f_num + int(second_number))
if self.math == "multiplication":
self.number_entry.insert(0, self.f_num * int(second_number))
if self.math == "division":
self.number_entry.insert(0, self.f_num / int(second_number))
if self.math == "floor_div":
self.number_entry.insert(0, self.f_num // int(second_number))
if self.math == "modulus":
self.number_entry.insert(0, self.f_num % int(second_number))
def button_subtract(self):
first_number = self.number_entry.get()
self.math = "subtraction"
self.f_num = int(first_number)
self.number_entry.delete(0, tk.END)
def button_multiply(self):
first_number = self.number_entry.get()
self.math = "multiplication"
self.f_num = int(first_number)
self.number_entry.delete(0, tk.END)
def button_divide(self):
first_number = self.number_entry.get()
self.math = "division"
self.f_num = int(first_number)
self.number_entry.delete(0, tk.END)
def button_floor_div(self):
first_number = self.number_entry.get()
self.math = "floor_div"
self.f_num = int(first_number)
self.number_entry.delete(0, tk.END)
def button_modulus(self):
first_number = self.number_entry.get()
self.math = "modulus"
self.f_num = int(first_number)
self.number_entry.delete(0, tk.END)
def button_sqrt(self):
number = float(self.number_entry.get())
result = sqrt(number)
if result.is_integer():
self.number_entry.delete(0, tk.END)
self.number_entry.insert(0, int(result))
else:
self.number_entry.delete(0, tk.END)
self.number_entry.insert(0, result)
def button_neg(self):
current = self.number_entry.get()
if current.startswith("-"):
current = current[1:]
else:
current = "-" + current
self.number_entry.delete(0, tk.END)
self.number_entry.insert(0, current)
if __name__ == '__main__':
root = tk.Tk()
calc = Calculator(root)
root.mainloop()
Подведем итоги
В этой статье мы рассмотрели основы создания GUI для Python-программ и научились использовать основные виджеты Tkinter. В следующей главе будем изучать основы разработки игр с Pygame.
Содержание самоучителя
- Особенности, сферы применения, установка, онлайн IDE
- Все, что нужно для изучения Python с нуля – книги, сайты, каналы и курсы
- Типы данных: преобразование и базовые операции
- Методы работы со строками
- Методы работы со списками и списковыми включениями
- Методы работы со словарями и генераторами словарей
- Методы работы с кортежами
- Методы работы со множествами
- Особенности цикла for
- Условный цикл while
- Функции с позиционными и именованными аргументами
- Анонимные функции
- Рекурсивные функции
- Функции высшего порядка, замыкания и декораторы
- Методы работы с файлами и файловой системой
- Регулярные выражения
- Основы скрапинга и парсинга
- Основы ООП: инкапсуляция и наследование
- Основы ООП: абстракция и полиморфизм
- Графический интерфейс на Tkinter
- Основы разработки игр на Pygame
- Основы работы с SQLite
- Основы веб-разработки на Flask
- Основы работы с NumPy
- Основы анализа данных с Pandas
Какие трудности у вас возникают при создании GUI на Python?