🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Расскажем о преимуществах и недостатках Tkinter, изучим основы создания GUI и разберемся в особенностях компоновки виджетов с помощью pack(), place() и grid(). В конце статьи – 10 практических заданий по разработке GUI для Python-программ.
🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Графический интерфейс для программы на 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()

    
🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Позиционирование окна в центре экрана

Чтобы разместить окно 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()

    

Теперь окно расположено точно в центре экрана:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Размещение элементов интерфейса в 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()

    
🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

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()

    
🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

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()

    
🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

В целом, 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()

    
🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Метод 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()

    
🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Назначение кнопке анонимной функции:

        import tkinter as tk

root = tk.Tk()

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

root.mainloop()

    
🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Связывание кнопки с частично примененной функцией:

        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()

    
🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Практика

Задание 1

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

Ожидаемый результат:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Решение:

        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 после нажатия на кнопку.

Ожидаемый результат:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Решение:

        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 количество слов и символов.

Ожидаемый результат:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter
        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 модуль).

Ожидаемый результат:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Решение:

        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 секунд.

Ожидаемый результат:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Решение:

        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.

Ожидаемый результат:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Решение:

        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-значение.

Ожидаемый результат:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Решение:

        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 включительно.

Ожидаемый результат:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Решение:

        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 для вывода объектов разного типа на отдельных вкладках. Реализуйте всплывающее окно для вывода полной информации об издании.

Ожидаемый результат:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Решение:

        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 калькулятор, который:

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

Кроме того, программа должна поддерживать очистку ввода.

Ожидаемый результат:

🐍 Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Решение:

        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.

***

Содержание самоучителя

  1. Особенности, сферы применения, установка, онлайн IDE
  2. Все, что нужно для изучения Python с нуля – книги, сайты, каналы и курсы
  3. Типы данных: преобразование и базовые операции
  4. Методы работы со строками
  5. Методы работы со списками и списковыми включениями
  6. Методы работы со словарями и генераторами словарей
  7. Методы работы с кортежами
  8. Методы работы со множествами
  9. Особенности цикла for
  10. Условный цикл while
  11. Функции с позиционными и именованными аргументами
  12. Анонимные функции
  13. Рекурсивные функции
  14. Функции высшего порядка, замыкания и декораторы
  15. Методы работы с файлами и файловой системой
  16. Регулярные выражения
  17. Основы скрапинга и парсинга
  18. Основы ООП: инкапсуляция и наследование
  19. Основы ООП: абстракция и полиморфизм
  20. Графический интерфейс на Tkinter
  21. Основы разработки игр на Pygame
  22. Основы работы с SQLite
  23. Основы веб-разработки на Flask
  24. Основы работы с NumPy
  25. Основы анализа данных с Pandas

МЕРОПРИЯТИЯ

Какие трудности у вас возникают при создании GUI на Python?

ВАКАНСИИ

Добавить вакансию

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ