Гид по технологиям

Как создать простое приложение Paint на Python с Tkinter и Pillow

6 min read Development Обновлено 12 Apr 2026
Paint на Python: Tkinter + Pillow — руководство
Paint на Python: Tkinter + Pillow — руководство

Важно: все исходные блоки кода сохранены и работоспособны в стандартной среде Python 3 при установленных пакетах tk и pillow.

Коротко о том, что вам понадобится

  • Python 3.7+ (рекомендуется 3.8+). Если у вас Linux, убедитесь, что установлены системные пакеты для tkinter. На Windows и macOS Tkinter обычно поставляется вместе с Python.
  • Пакеты: Tkinter (стандарт), Pillow.

Установка:

pip install tk pillow

Изображение интерфейса

Кисть, краски и лист бумаги для рисования

Краткое описание приложения

Это простое приложение Paint позволяет выбирать цвет кисти, менять размер, стирать, очищать холст, менять фон и сохранять изображение. Оно подходит как учебный проект, прототип для детских приложений и для быстрых аннотаций.

Главные модули и идеи

  • Tkinter — стандартная библиотека для построения оконных приложений в Python. Виджеты: Label, Button, Canvas, Scale и т.д.
  • Pillow (форк PIL) — для захвата экрана и манипуляций с изображениями.
  • Canvas в Tkinter рисует примитивы (oval, line, rectangle, text, image). Мы используем create_oval для имитации мазка кисти.

Исходная структура кода приложения

Ниже приведена основная структура класса DrawApp и ключевые методы. Блоки кода сохранены в исходном виде и работают как концепт.

import tkinter as tk  
from tkinter.ttk import Scale  
from tkinter import colorchooser, filedialog, messagebox  
import PIL.ImageGrab as ImageGrab  
  
class DrawApp:  
    def __init__(self, root):  
        self.root = root  
        self.root.title("Kids' Paint App")  
        self.root.attributes("-fullscreen", True)  
        self.pointer = "black"  
        self.erase = "white"  
        self.setup_widgets()

Далее мы настраиваем виджеты, палитру, кнопки и канву:

    def setup_widgets(self):  
        self.title_label = tk.Label(  
            self.root,  
            text="Kids' Paint App",  
            font=("Comic Sans MS", 30),  
            bg="lightblue",  
            fg="purple",  
        )  
        self.title_label.pack(fill=tk.X, pady=10)  
        self.color_frame = tk.LabelFrame(  
            self.root,  
            text="Colors",  
            font=("Comic Sans MS", 15),  
            bd=5,  
            relief=tk.RIDGE,  
            bg="white",  
        )  
        self.color_frame.place(x=10, y=80, width=90, height=180)

Палитра цветов и кнопки управления:

        colors = [  
            "blue",  
            "red",  
            "green",  
            "orange",  
            "violet",  
            "black",  
            "yellow",  
            "purple",  
            "pink",  
            "gold",  
            "brown",  
            "indigo",  
        ]  
        i, j = 0, 0  
        for color in colors:  
            tk.Button(  
                self.color_frame,  
                bg=color,  
                bd=2,  
                relief=tk.RIDGE,  
                width=3,  
                command=lambda col=color: self.select_color(col),  
            ).grid(row=i, column=j, padx=2, pady=2)  
            i += 1  
            if i == 4:  
                i = 0  
                j = 1

Кнопки «Ластик», «Очистить», «Сохранить» и «Фон», а также слайдер размера:

        self.eraser_btn = tk.Button(  
            self.root,  
            text="Eraser",  
            bd=4,  
            bg="white",  
            command=self.eraser,  
            width=9,  
            relief=tk.RIDGE,  
            font=("Comic Sans MS", 12),  
        )  
        self.eraser_btn.place(x=10, y=310)  
        self.clear_screen_btn = tk.Button(  
            self.root,  
            text="Clear Screen",  
            bd=4,  
            bg="white",  
            command=self.clear_screen,  
            width=12,  
            relief=tk.RIDGE,  
            font=("Comic Sans MS", 12),  
        )  
        self.clear_screen_btn.place(x=10, y=370)  
        self.save_as_btn = tk.Button(  
            self.root,  
            text="Save Drawing",  
            bd=4,  
            bg="white",  
            command=self.save_as,  
            width=12,  
            relief=tk.RIDGE,  
            font=("Comic Sans MS", 12),  
        )  
        self.save_as_btn.place(x=10, y=430)  
        self.bg_btn = tk.Button(  
            self.root,  
            text="Background",  
            bd=4,  
            bg="white",  
            command=self.canvas_color,  
            width=12,  
            relief=tk.RIDGE,  
            font=("Comic Sans MS", 12),  
        )  
        self.bg_btn.place(x=10, y=490)  
        self.pointer_frame = tk.LabelFrame(  
            self.root,  
            text="Size",  
            bd=5,  
            bg="white",  
            font=("Comic Sans MS", 15, "bold"),  
            relief=tk.RIDGE,  
        )

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

        self.pointer_frame.place(x=10, y=580, height=150, width=70)  
        self.pointer_size = Scale(  
            self.pointer_frame, orient=tk.VERTICAL, from_=48, to=1, length=120  
        )  
        self.pointer_size.set(1)  
        self.pointer_size.grid(row=0, column=1, padx=15)  
        self.canvas = tk.Canvas(  
            self.root, bg="white", bd=5, relief=tk.GROOVE, height=650, width=1300  
        )  
        self.canvas.place(x=160, y=120, anchor="nw")  
        self.canvas.bind("", self.paint)

Как работает рисование

Метод paint рисует маленькие овалы по координатам курсора, имитируя мазок кисти. Здесь вы можете менять форму — рисовать линии, прямоугольники или полигоны.

    def paint(self, event):  
        x1, y1 = (event.x - 2), (event.y - 2)  
        x2, y2 = (event.x + 2), (event.y + 2)  
        self.canvas.create_oval(  
            x1,  
            y1,  
            x2,  
            y2,  
            fill=self.pointer,  
            outline=self.pointer,  
            width=self.pointer_size.get(),  
        )

Функции выбора цвета, ластика и очистки холста:

    def select_color(self, col):  
        self.pointer = col   
  
    def eraser(self):  
        self.pointer = self.erase   
  
    def clear_screen(self):  
        self.canvas.delete("all")

Изменение фонового цвета холста (цветовой диалог возвращает RGB и HEX):

    def canvas_color(self):  
        color = colorchooser.askcolor()  
        if color:  
            self.canvas.configure(background=color[1])  
            self.erase = color[1]

Сохранение изображения: захват экрана + обрезка области холста и запись файла.

    def save_as(self):  
        file_path = filedialog.asksaveasfilename(  
            defaultextension=".jpg", filetypes=[("Image files", "*.jpg")]  
        )  
        if file_path:  
            try:  
                y = 148  
                x = 200  
                y1 = 978  
                x1 = 1840  
                ImageGrab.grab().crop((x, y, x1, y1)).save(file_path)  
                messagebox.showinfo("Save Drawing", "Image file saved successfully!")  
            except Exception as e:  
                messagebox.showerror("Error", f"Failed to save the image file: {e}")

Запуск приложения:

if __name__ == "__main__":  
    root = tk.Tk()  
    app = DrawApp(root)  
    root.mainloop()

Тестирование: как проверить функциональность

После запуска вы увидите палитру, кнопки, слайдер и холст.

Начальный экран приложения Paint

Демонстрация рисования разными цветами:

Рисование различными красками

Увеличьте размер ластика и потестируйте его работу:

Увеличение размера и стирание

Изменение фона и очистка холста:

Очистка экрана и изменение фона

Сохранение результата:

Сохранение рисунка как изображения

Как улучшить приложение — практические идеи

Ниже — список конкретных улучшений и краткие указания по реализации.

  • Форма кисти: добавить выбор между круглой и плоской кистью, рисование линиями (create_line) с параметрами smooth.
  • Непрозрачность (alpha): сохранить временный слой в Pillow и смешивать, либо рисовать примитивы с предварительно вычисленным цветом с альфой (Tkinter в чистом виде не поддерживает альфу для canvas-примитивов — нужна отрисовка в Pillow и обновление изображения на canvas).
  • Отмена/Повтор (Undo/Redo): хранить стек операций (списки id объектов на холсте) и по операции удалять/восстанавливать объекты.
  • Добавление текста и стикеров: использовать create_text и create_image; для изображений — поддерживать загрузку PNG с прозрачностью через PhotoImage.
  • Масштабирование и переворот изображений: использовать Pillow (resize, transpose) и обновлять изображение на canvas.

Пример: реализация Undo простым стеком

  • При каждой операции рисования накапливайте id добавленных примитивов в группу и пушьте группу в стек undo.
  • Для undo извлекайте последнюю группу и удаляйте все id из неё.
  • Для redo храните второй стек, куда перемещаете группы при undo.

Это даёт базовую историю действий без полного снимка холста.

Когда такой подход не подходит

  • Для профессиональных графических редакторов с поддержкой слоёв, слоёв с blend-mode и миллионными кистями лучше использовать специализированные движки и библиотеки (например, PyQt/PySide с QPainter или интеграция с C++-библиотеками).
  • Для сенсорных приложений на мобильных платформах стоит рассмотреть Kivy или нативные SDK.

Альтернативные подходы и инструменты

  • PyQt / PySide: более мощный набор виджетов и расширенные возможности рендеринга.
  • Kivy: подходит для мобильных приложений и сенсорного ввода, поддерживает мультитач.
  • Web-приложение: HTML5 canvas + JS — удобно для кроссплатформенного распространения.

Ментальные модели и эвристики для разработки графических редакторов

  • Модель слоёв: представьте холст как стек слоёв; каждая операция рисования — изменение верхнего слоя.
  • Политика сохранения: экономьте память, сохраняя диффы операций, если важна история undo.
  • Производительность: рисуйте только изменённые области (dirty rectangles), когда холст становится большим.

Критерии приёмки

  • Приложение открывается и не падает при базовых действиях: рисование, смена цвета, стирание, очистка и сохранение изображения.
  • Сохранённый файл открывается в стандартных просмотрщиках и содержит ожидаемую область холста.
  • Размер кисти изменяется корректно, цвет и фон применяются моментально.
  • Undo/Redo (если реализовано) корректно откатывают/возвращают последние операции.

Чек-листы по ролям

Разработчик:

  • Запустить приложение на целевой платформе.
  • Покрыть edge-case: нулевой или очень большой размер кисти.
  • Обработать отказ сохранения (нет прав записи).

Тестировщик:

  • Проверить корректность обрезки при сохранении (координаты x,y,x1,y1).
  • Проверить работу colorchooser на разных ОС.
  • Тестировать производительность при плотном рисовании.

Дизайнер/UX:

  • Проверить читаемость кнопок и меток при разных DPI.
  • Убедиться, что элементы управления доступны детям (если это детское приложение).

Тестовые случаи и приёмочные критерии

  • Рисование: удерживая левую кнопку и двигая мышью, на холсте появляются мазки соответствующего цвета и размера.
  • Ластик: при нажатии на Eraser холст стирается цветом фона; ширина ластика соответствует ползунку.
  • Очистка: Clear Screen удаляет все объекты с холста.
  • Сохранение: при выборе пути файл создаётся, размер и содержимое соответствуют видимой области холста.
  • Смена фона: Background открывает диалог цвета и изменяет цвет холста и поведение ластика.

Практические советы по локализации и совместимости (для русскоязычных пользователей)

  • Шрифты: для русских текстов избегайте шрифтов, не содержащих кириллицу. Comic Sans MS содержит кириллицу, но для профессионального интерфейса лучше использовать системные шрифты (например, Arial, Tahoma) или локализованные семейства.
  • Кодировка: убедитесь, что файлы с ресурсами сохранены в UTF-8.
  • Путь сохранения: на Windows пути могут содержать кириллицу; filedialog.asksaveasfilename корректно возвращает такие пути при использовании UTF-8.

Безопасность и приватность

  • Сохранение изображений выполняется локально; не отправляйте пользовательские рисунки на удалённые серверы без явного согласия.
  • При вызове filedialog всегда проверяйте возвращаемое значение и обработайте возможные исключения записи на диск.

Примеры расширений: кодовые сниппеты

Пример: рисование сглаженных линий вместо множества овалов (упрощённо):

# внутри класса DrawApp
self.last_x, self.last_y = None, None
self.canvas.bind('', self.on_button_down)
self.canvas.bind('', self.draw_line)

def on_button_down(self, event):
    self.last_x, self.last_y = event.x, event.y

def draw_line(self, event):
    if self.last_x is not None and self.last_y is not None:
        self.canvas.create_line(self.last_x, self.last_y, event.x, event.y,
                                fill=self.pointer, width=self.pointer_size.get(), capstyle=tk.ROUND, smooth=True)
    self.last_x, self.last_y = event.x, event.y

Этот подход даёт более плавный мазок и меньше объектов на холсте.

Mini‑методология разработки — быстрый план проекта (микро- roadmap)

  1. Прототип: реализовать рисование, палитру и сохранение.
  2. Стабилизация: обработка ошибок, тесты на разных ОС.
  3. Удобство: добавить undo/redo, выбор кисти, прозрачность.
  4. Производительность: оптимизация отрисовки и уменьшение количества объектов.
  5. Локализация: перевести UI, проверить шрифты и кодировки.

Краткий справочник терминов

  • Canvas — виджет для рисования примитивов.
  • Pillow — библиотека для обработки изображений в Python.
  • ImageGrab — класс Pillow для захвата экрана.
  • B1-Motion — событие «левая кнопка мыши + движение».

Резюме

  • Простое приложение Paint на Tkinter — отличный учебный проект, позволяющий изучить GUI, обработку событий и работу с изображениями через Pillow.
  • Основные функции: выбор цвета, масштаб кисти, ластик, очистка, смена фона, сохранение.
  • Для продвинутого функционала (слои, альфа, производительность) рассмотрите использование Pillow для рендеринга и/или переход на PyQt/Kivy.

Дополнительные идеи: интеграция с мультитачем, экспорт в PNG с прозрачностью, плагины для кистей и пресетов.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Убрать рекламу в мобильных играх на iPhone и iPad
Мобильные игры

Убрать рекламу в мобильных играх на iPhone и iPad

Как посмотреть подписчиков на YouTube
YouTube

Как посмотреть подписчиков на YouTube

Как обновить драйверы AMD Radeon в Windows 11
Драйверы

Как обновить драйверы AMD Radeon в Windows 11

Как использовать старый ПК как домашний медиа‑сервер
Домашние серверы

Как использовать старый ПК как домашний медиа‑сервер

Защита от зеркалирования смартфона
Кибербезопасность

Защита от зеркалирования смартфона

Безопасная утилизация умных устройств
Безопасность

Безопасная утилизация умных устройств