Создаем Paint с нуля за вечер часть 1: окно, холст и простая кисть
12.12.2025
Время прочтения: 20-25 минут.
Что нас ждёт
Начнём с самого простого: сделаем программу, которая вообще умеет рисовать линию мышкой. Пока нас не интересуют цвета, толщина кисти и пипетка — только белый лист и чёрный фломастер.
✅ Что сделаем: окно + холст + рисование мышью.
⏭️ Что будет дальше: выбор цвета, размер кисти, очистка, пипетка.

Создадим окно приложения
Представьте себе обычный лист бумаги на столе. Лист — это наш Canvas, специальный виджет Tkinter, на котором можно рисовать. Стол вокруг листа — это окно tk.Tk(). Сначала мы создадим «стол», потом положим на него «лист», а уже потом научим мышку оставлять следы на нём, как будто это маркер. Для начала нам нужно скачать и добавить модуль Tkinter, а также задать некоторые переменные. !!Добавить ссылку на наш гайд по скачке!!
import tkinter as tk
import time
# Цвета
green_color = "#00b259" # зеленый
orange_color = "#f15a31" # оранжевый
purple_color = "#bd56a0" # фиолетовый
Цвет в Python часто задают так: green_color="#00b259". Это HEX‑код (шестнадцатеричный формат): в нём “зашиты” доли красного, зелёного и синего — чтобы получить нужный цвет. Не переживайте: запоминать формулы не надо, достаточно знать, что это просто удобный способ выбрать любой оттенок.
Tkinter поможет нам при создании окна для игры. Команда root = tk.Tk() создаёт главное окно. Ему можно дать фон, чтобы белый холст красиво выделялся.
"""Создаём главное окно и всё, что на нём лежит."""
# Создаём главное окно программы
root = tk.Tk() # главное окно
root.configure(bg=green_color) # фон вокруг холста
root.title("Рисовалка (часть 1)")
Результат на данном этапе: появляется окно с фоном, на котором скоро будет холст:

Пустой холст
Теперь создадим пустой canvas — это будущий холст. Он делается через tk.Canvas(...): прямоугольная область, где мы задаём ширину, высоту и фон (то есть “цвет бумаги”). , размещаем холст внутри рамки и растягиваем его на всё доступное пространство.
"""Создаём холст для рисования и располагаем его в рамке."""
# Декоративная рамка вокруг холста, чтобы управлять его расположением отдельно
canvas_frame = tk.Frame(root)
canvas_frame.pack(side="top", fill="both", expand=True, padx=10, pady=10)
# Сам холст Canvas, на котором можно рисовать
canvas = tk.Canvas(
canvas_frame, #располагаем его в нашей рамке
width=900, # делаем базовые размеры холста
height=400,
bg="white", # фон – белый лист
)
canvas.pack(fill="both", expand=True) #чтобы наш холст растянулся на всё окно
Что тут важно в размещении canvas_frame.pack:
-
side="top"— рамка прижимается к верхней части окна. -
expand=Trueиfill="both"— холст растягивается, если окно меняет размер (чтобы “лист” не был маленьким островком посреди экрана). -
padx=10,pady=10— отступы по краям, чтобы всё выглядело аккуратно и не “липло” к окну.
Вот получившийся холст: белая область внутри рамки — готовый “лист”:

Цикл игры — её сердце
Мы запустим программу и обработку событий “вручную”, чтобы почувствовать, как работает игровой цикл: программа постоянно крутится, обновляет окно и реагирует на действия пользователя.
Но если не поставить ограничение, цикл будет работать так быстро, как позволит компьютер — и вы получите не рисовалку, а тест на выживание вашего процессора. Поэтому добавляем маленькую паузу time.sleep(0.01) — 10 миллисекунд, чтобы контролировать частоту обновления.
Мы создадим переменную running = True, чтобы программа не завершалась сразу. Теперь после отрисовки интерфейса запускаем цикл: в каждом “кадре” обновляем Tkinter и обрабатываем события (мышь, закрытие окна и т. п.).
# Флаг для "игрового" цикла
running = True # пока True — окно живёт
"""Игровой цикл: пока running == True, окно живёт и реагирует на события."""
while running:
root.update() # Обрабатываются события: клик мыши, движение, закрытие окна
time.sleep(0.01) # Небольшая пауза, чтобы не грузить процессор
Примерно так же работают и игры: постоянно крутясь в цикле, пересчитывают позиции объектов и перерисовывают кадр.
Мышь: нажал → веду → отпустил
С рисованием нам поможет Tkinter: он умеет вызывать наши функции, когда происходит событие (например, нажатие мышки). Для этого есть bind — “привязка”: мы говорим холсту, какую функцию вызывать на какое действие.
Перед запуском основного цикла привяжем:
-
нажали левую кнопку →
on_mouse_down -
ведём мышь с зажатой кнопкой →
on_mouse_move
# Привязываем обработчики мыши:
# нажали кнопку, двигаем с зажатой кнопкой, отпустили кнопку
canvas.bind("<ButtonPress-1>", on_mouse_down)
canvas.bind("<B1-Motion>", on_mouse_move)
Tkinter передаёт в эти функции объект event . В нём лежат координаты мыши: event.x и event.y. По ним мы и будем рисовать. Линия на Canvas рисуется командой create_line(x1, y1, x2, y2, ...). : она добавляет на холст новый “кусочек линии”. Мы задаём координаты начала и концы, цвет и толщину. А для создания одной точки при нажатии мы используем create_oval(x1, y1, x2, y2, ...): в ней координаты используются для создания круга внутри заданной координатами квадратной рамки. Ещё сделаем закруглённые края и сглаживание, чтобы мазок выглядел приятнее (а не как след от табуретки) и сразу введём необходимые переменные.
# Зададим переменные координат
last_x = None
last_y = None
# Параметры кисти
current_color = "#000000" # по умолчанию чёрный маркер
brush_size = 8 # толщина линии
def on_mouse_down(event):
"""Начинаем рисовать: запоминаем точку нажатия и ставим первую 'точку'."""
global last_x, last_y # нужно для того чтобы мы меняли наши глобальные переменные, а не делали новые
# запоминаем, где нажали
last_x = event.x
last_y = event.y
# Рисуем совсем короткую линию длиной 1 пиксель, чтобы появился след
canvas.create_oval(
event.x - brush_size // 2 , event.y - brush_size // 2, # левая верхняя точка
event.x + brush_size // 2 , event.y + brush_size // 2, # правая нижняя точка
fill=current_color, # цвет линии – текущий цвет кисти
)
Идея простая: нажали мышь — запоминаем эту точку. Когда ведём мышь — каждый раз соединяем прошлую точку с новой короткой линией. Много маленьких отрезков подряд выглядят как плавный мазок. Отпустили кнопку — перестаём рисовать.
def on_mouse_move(event):
"""Продолжаем линию, если кнопка зажата и есть последняя точка."""
global last_x, last_y
if last_x is not None:
# Рисуем отрезок от прошлой точки к новой
canvas.create_line(
last_x, last_y, # точка начала линии
event.x, event.y, # точка конца линии
fill=current_color, # цвет
width=brush_size, # ширина
capstyle="round", # закругление краёв линии
smooth=True # легкое сглаживание
)
# Переносим "последнюю точку" в текущую позицию мыши
last_x = event.x
last_y = event.y
Собираем всё вместе
Функций пока немного: мы просто рисуем чёрной кистью по белому листу. Но в следующей части это исправим.

import tkinter as tk
import time
def on_mouse_down(event):
"""Начинаем рисовать: запоминаем точку нажатия и ставим первую 'точку'."""
global last_x, last_y
last_x = event.x
last_y = event.y
# Рисуем совсем короткую линию длиной 1 пиксель, чтобы появился след
canvas.create_oval(
event.x - brush_size // 2 , event.y - brush_size // 2, # левая верхняя точка
event.x + brush_size // 2 , event.y + brush_size // 2, # правая нижняя точка
fill=current_color, # цвет линии – текущий цвет кисти
)
def on_mouse_move(event):
"""Продолжаем линию, если кнопка зажата и есть последняя точка."""
global last_x, last_y
if last_x is not None:
# Рисуем отрезок от прошлой точки к новой
canvas.create_line(
last_x, last_y, # точка начала линии
event.x, event.y, # точка конца линии
fill=current_color, # цвет
width=brush_size, # ширина
capstyle="round", # закругление краёв линии
smooth=True # легкое сглаживание
)
# Переносим "последнюю точку" в текущую позицию мыши
last_x = event.x
last_y = event.y
# Главное окно программы
root = None
# Параметры кисти
current_color = "#000000" # чёрный цвет по умолчанию
brush_size = 8 # толщина кисти по умолчанию
# Цвета
green_color = "#00b259" # зеленый
orange_color = "#f15a31" # оранжевый
purple_color = "#bd56a0" # фиолетовый
# Последняя точка, где была мышь при рисовании (None = не рисуем)
last_x = None
last_y = None
# Флаг для игрового цикла while
running = True
"""Создаёт окно и интерфейс."""
root = tk.Tk() # Создаём главное окно программы
root.configure(bg=green_color) # фон вокруг холста, чтобы белый "лист" выделялся
# Создаём все элементы интерфейса
"""Создаём рамку и холст для рисования."""
# Декоративная рамка вокруг холста, чтобы можно было просто контролировать его размер
canvas_frame = tk.Frame(root, bg=orange_color, bd=2, relief="ridge")
canvas_frame.pack(side="top", fill="both", expand=True, padx=10, pady=10)
# Сам холст Canvas, на котором можно рисовать
canvas = tk.Canvas(
canvas_frame,
width=900,
height=400,
bg="white", # фон – белый лист
)
canvas.pack(fill="both", expand=True)
# Привязываем обработчики мыши:
# нажали кнопку, двигаем с зажатой кнопкой, отпустили кнопку
canvas.bind("<ButtonPress-1>", on_mouse_down)
canvas.bind("<B1-Motion>", on_mouse_move)
"""Игровой цикл: пока running == True, окно живёт и реагирует на события."""
while running:
root.update() # Обрабатываются события: клик мыши, движение, закрытие окна
time.sleep(0.01) # Небольшая пауза для контроля количества кадров
