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

Как создать простое приложение 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
Автор
Редакция

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

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро