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

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

7 min read Python GUI Обновлено 18 Dec 2025
Paint на Python с Tkinter и Pillow
Paint на Python с Tkinter и Pillow

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

Простое приложение Paint — один из самых распространённых видов программного обеспечения на настольных компьютерах. Оно позволяет рисовать без страха ошибиться, быстро выборать любой цвет и мгновенно менять толщину мазков. Такое приложение удобно для создания логотипов, концептов интерфейса или для аннотаций на диаграммах.

В этой статье вы узнаете, как собрать работающее приложение Paint на Python, как устроены основные части кода, какие возможности можно добавить и как тестировать и распространять программу.

Что потребуется для работы

  • Python 3.6+ (рекомендуется последняя стабильная версия).
  • Модули Tkinter (обычно поставляется с Python) и Pillow.

Pояснение: Tkinter — стандартная библиотека для создания оконных приложений в Python. Pillow — форк PIL, библиотека для работы с изображениями.

Установка (в терминале):

pip install tk pillow

Важно: на некоторых системах (особенно на Linux) пакет tk может устанавливаться через менеджер пакетов системы (apt, dnf и т. п.). Если import tkinter не работает, установите системный пакет, например, sudo apt install python3-tk.

Структура приложения и основной класс

Приложение организовано как класс DrawApp, который инициализирует окно, настраивает элементы управления и канву для рисования. Ниже — сокращённый и отформатированный пример кода, полностью рабочий при правильной вставке в файл .py.

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

В этом фрагменте мы:

  • задаём заголовок окна;
  • разворачиваем окно во весь экран (можно убрать для оконного режима);
  • устанавливаем текущий цвет рисования и цвет ластика;
  • вызываем метод setup_widgets, который создаёт интерфейс.

Виджеты интерфейса: панель цветов, кнопки, слайдер и канва

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

Выбор фона происходит через стандартный диалог colorchooser. Метод возвращает кортеж (RGB, hex). При выборе фона ластик подстраивается под новый цвет фона.

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

Сохранение изображения с помощью Pillow

Для сохранения используется PIL.ImageGrab: делается снимок экрана, затем он обрезается по координатам, соответствующим канве. Координаты в примере подобраны для определённого разрешения — их нужно подогнать под ваше окно.

    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}")

Совет: вместо глобального ImageGrab можно экспортировать содержимое канвы в postscript и затем конвертировать через Pillow, что часто даёт более предсказуемый результат и не зависит от координат экрана.

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

В самом конце создаём экземпляр Tk и запускаем цикл событий:

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

Тестирование встроенных функций

При запуске вы увидите приложение с палитрой, четырьмя кнопками, слайдером и холстом для рисования:

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

  • Выберите цвет и рисуйте левой кнопкой мыши.

Рисование разными цветами на холсте

  • Нажмите «Eraser» и измените размер ластика, передвинув слайдер вверх.

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

  • Кнопка «Clear Screen» очищает холст. Кнопка «Background» открывает палитру для смены фона.

Очистка холста и изменение цвета фона

  • Сохранение рисунка вызывает диалог выбора файла и сохраняет изображение.

Сохранение рисунка в файл изображения

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

Ниже — идеи и рекомендации, которые расширят функциональность и надёжность приложения.

  • Добавить выбор формы кисти: круглая, квадратная, линия. Используйте create_rectangle, create_line или create_polygon.
  • Добавить прозрачность кисти (алфа) с композитингом через Pillow при сохранении.
  • Реализовать слои: хранить объекты в отдельных группах, рендерить их по очереди, сохранять как объединённое изображение.
  • Добавить Undo/Redo: ведите стек действий и откатывайте/восстанавливайте последние команды.
  • Поддержка штампов и стикеров: загрузка PNG с прозрачностью и вставка на канву.
  • Инструменты трансформации: масштабирование и поворот объектов; используйте Pillow для изменения изображений.

Альтернативные подходы к реализации

  • PyQt/PySide: даёт более современный вид UI и сильные графические возможности (QPainter). Подходит для более сложных интерфейсов.
  • Kivy: кроссплатформенный фреймворк, удобен для сенсорных экранов и мобильных устройств.
  • Веб-версия: HTML5 canvas + Flask/Django на бэкенде. Позволяет легко поделиться приложением через браузер.
  • Использовать Cairo/Skia для аппаратного рендеринга и более точного управления векторной графикой.

Когда выбирать: для простых настольных утилит — Tkinter; для коммерческого продукта с насыщенной графикой — PyQt/PySide или нативная графика.

Ментальные модели и эвристики при проектировании UX

  • «Путь к цели» — минимизируйте количество кликов до действия (цвет → кисть → рисовать).
  • «Обратимость» — всегда делайте Undo удобным и быстрым.
  • «Предсказуемость» — показ текущего цвета и размера кисти рядом с курсором или в интерфейсе.
  • «Доступность» — клавиатурные сокращения и крупные кнопки для детей и тач-экранов.

Мини‑методология разработки (быстрая итерация)

  1. Прототип: запустить базовый canvas + рисование «точками».
  2. Добавить селектор цвета и размер кисти.
  3. Реализовать базовые кнопки (clear, save, background).
  4. Тестировать UX на целевой аудитории (дети/взрослые дизайнеры).
  5. Добавлять слои и Undo, затем оптимизировать сохранение и экспорт.

Роль‑ориентированные чеклисты

Для разработчика:

  • Проверить корректность импорта tkinter и pillow.
  • Обеспечить обработку исключений при сохранении.
  • Настроить дебаг логирование для координат канвы.

Для дизайнера:

  • Подобрать читаемую цветовую палитру.
  • Оценить размеры кнопок и шрифты для целевой аудитории.

Для тестировщика:

  • Протестировать рисование при разной скорости перемещения мыши.
  • Проверить сохранение на разных разрешениях экрана.
  • Проверить работу диалогов выбора файлов и цвета.

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

  • Приложение запускается без ошибок на целевой системе.
  • Можно рисовать и изменять толщину линии.
  • Цвета палитры применяются корректно.
  • Сохранение создаёт корректный файл изображения.

Тестовые сценарии и примеры приёмки

  1. Нарисовать несколько разноцветных линий, сохранить файл, открыть его во внешнем просмотре — изображение соответствует.
  2. Изменить фон на контрастный цвет и проверить, что ластик стирает до этого цвета.
  3. Быстро проводить мышью по холсту — не должно быть пропусков в линии.
  4. Отмена/возврат действий (если реализовано) — проверка стеков.

Совместимость и рекомендации по платформам

  • Windows: ImageGrab работает стабильно.
  • macOS: ImageGrab требует разрешений на запись экрана; запросите у пользователя разрешение.
  • Linux: ImageGrab может не работать на всех окружениях; используйте экспорт в postscript из Canvas и конвертацию через Pillow.

Совет: при кроссплатформенной поддержке реализуйте два способа сохранения и выбирайте подходящий в рантайме.

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

  • При сохранении файлов используйте filedialog.asksaveasfilename, чтобы пользователь сам указал путь.
  • Не отправляйте снимки экрана на сторонние сервисы без явного согласия.
  • Для корпоративного использования проверьте требования к хранению и передаче изображений (GDPR/локальные правила).

Когда этот подход не подходит

  • Если вам нужен векторный редактор со слоями и трансформациями — лучше использовать инструменты, ориентированные на вектор (SVG, Cairo, Skia).
  • Для мобильных приложений предпочтительнее Kivy или нативные SDK.

Быстрый чек-лист улучшений и приоритеты (Impact × Effort)

  • Undo/Redo — высокий эффект, средняя сложность.
  • Слои — высокий эффект, высокая сложность.
  • Поддержка прозрачности и PNG — средний эффект, низкая сложность.
  • Выбор формы кисти — средний эффект, низкая сложность.

Короткое руководство по миграции на PyQt (если нужно)

  1. Заменить tkinter.Canvas на QWidget с перехватом paintEvent.
  2. Использовать QPainter для рисования линий и управления слоями.
  3. Для сохранения использовать QImage.save или экспорт в Pillow при необходимости.

Итог и дальнейшие шаги

Важно: начните с минимального набора функций и добавляйте улучшения по мере обратной связи. Тестируйте сохранение на целевых платформах и убедитесь в корректной обработке диалогов.

Ключевые направления развития: поддержка Undo, слоёв, различных типов кистей и экспорт в более формальные форматы (PNG с прозрачностью, SVG для векторной графики).

Завершая, напомню: код в статье — рабочая отправная точка. Подгоните координаты сохранения, адаптируйте интерфейс под размер окна и добавляйте функции, которые важны именно для вашей аудитории.

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

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

Как изменить голос Alexa и настройки речи
Умный дом

Как изменить голос Alexa и настройки речи

Установить VirtualBox и создать VM на Linux
Виртуализация

Установить VirtualBox и создать VM на Linux

Как пожаловаться на пользователя в Snapchat
соцсети

Как пожаловаться на пользователя в Snapchat

Связывание заметок в Apple Notes на iPhone
iOS

Связывание заметок в Apple Notes на iPhone

Лазерная гравировка по стеклу — практическое руководство
DIY

Лазерная гравировка по стеклу — практическое руководство

PayPal в Apple ID: добавить и удалить
Инструкции

PayPal в Apple ID: добавить и удалить