Создаем Paint с нуля за вечер №2: палитра R, G, B и окно текущего цвета
12.12.2025
Время прочтения: 20 - 25 минут.
Что нас ждёт
Рисовать одним чёрным маркером можно… примерно минуту. Потом рука тянется либо к цветам, либо к кнопке “закрыть” (и не обязательно в таком порядке). Так что добавляем цвет, причём не “5 кнопок на удачу”, а нормальное смешивание RGB, как в настоящих редакторах.
✅ Что сделаем: выбор цвета, окошко с отображением выбранного цвета
⏭️ Что будет дальше: выбор размера кисти, очистка, пипетка.
Если вы еще не читали предыдущие части, то перед началом советую ознакомиться.
!!Добавить ссылки на будущие и прошлые части!!

Панель управления: где живут ползунки и предпросмотр цвета
Чтобы управлять цветом, добавим три ползунка снизу:
-
R — красный
-
G — зелёный
-
B — синий
Каждый ползунок — это “сколько” этого цвета добавить. Смешивая их, можно получить почти любой оттенок. Рядом сделаем маленькое окно‑предпросмотр: прямоугольник, который показывает, каким цветом кисть рисует прямо сейчас.
Для этого внизу окна создаём новую панель controls_frame через tk.Frame(). (Frame — это просто “рамка‑контейнер”, чтобы аккуратно раскладывать элементы).
-
слева — область с тремя ползунками,
-
рядом — текст “Текущий цвет” и маленький цветной прямоугольник.
# НИЗ: панель управления
controls_frame = tk.Frame(root, bg=orange_color) # bg=orange_color это цвет фона внутри рамки
controls_frame.pack(side="bottom", fill="x", padx=10, pady=(0, 10)) # располагаем это окно и задаем размеры
# Слева – три ползунка R, G, B и их рамка внутри прошлой рамки controls_frame
sliders_frame = tk.Frame(controls_frame, bg=orange_color)
sliders_frame.pack(side="left", padx=10)
# это наша функция‑фабрика для ползунков, о ней чуть ниже
r_scale = create_color_scale(sliders_frame, "R", 0)
g_scale = create_color_scale(sliders_frame, "G", 1)
b_scale = create_color_scale(sliders_frame, "B", 2)
# По центру – окно текущего цвета
preview_frame = tk.Frame(controls_frame, bg=orange_color)
preview_frame.pack(side="left", padx=20) # Пододвигаем его к ползункам
Ползунок: Scale (двигаем — цвет меняется)
В Tkinter ползунок называется Scale. Ему задают:
-
диапазон значений (для RGB это 0…255, потому что у каждой компоненты столько вариантов),
-
направление (у нас горизонтально),
-
и
command— функция, которую Tkinter вызывает каждый раз, когда вы двигаете ползунок.
Именно эта функция и будет пересчитывать цвет кисти.
def create_color_scale(parent, name, column):
"""Создаёт один ползунок для компоненты цвета (R, G или B)."""
label = tk.Label(parent, text=name, fg="white", bg=orange_color) # делаем подпись для ползунка
label.grid(row=0, column=column)
scale = tk.Scale(
parent, # внутри какой рамки создаём
from_=0, # минимум
to=255, # максимум
orient="horizontal", # горизонтальный ползунок
length=200,
command=lambda value: update_color_from_sliders(), # вызываем при изменении ползунка
showvalue=True, # показываем значение на ползунке
bg=orange_color, # фоновый цвет
fg="white",
troughcolor=purple_color, # задний фон ползунка
highlightthickness=0 # убираем рамку вокруг ползунка
)
scale.grid(row=1, column=column, padx=5)
return scale
Окно “Текущий цвет”: маленький Canvas‑прямоугольник
Предпросмотр цвета делаем отдельным маленьким Canvas и прописываем в основном коде перед циклом игры. Идея простая: мы просто заливаем его фоном текущего цвета, и сразу видно, чем вы рисуете.
tk.Label( # добавляем надпись
preview_frame, # в нужной рамке
text="Текущий цвет",
fg="white",
bg=orange_color
).pack()
color_preview = tk.Canvas(
preview_frame, # в нужной рамке
width=80,
height=50,
bg=current_color, # фон = текущий цвет кисти
)
color_preview.pack(pady=5)
Чтобы не копировать один и тот же код три раза (и не превратить проект в сериал на 200 сезонов), мы и сделали функцию‑заготовку create_color_scale: она принимает рамку‑родителя в которой она появится, букву (“R”, “G”, “B”) и номер колонки — и создаёт подпись + ползунок.
Собираем R+G+B в один цвет
Теперь пишем update_color_from_sliders(). Она делает ровно две вещи:
-
берёт значения трёх ползунков,
-
собирает из них строку цвета вида
"#rrggbb"(шестнадцатеричная запись) и:-
сохраняет в
current_color, -
обновляет фон окна‑предпросмотра.
-
def update_color_from_sliders():
"""Читает значения трёх ползунков и обновляет текущий цвет кисти."""
global current_color
r = int(r_scale.get())
g = int(g_scale.get())
b = int(b_scale.get())
# Собираем цвет в формате "#rrggbb"
current_color = "#{:02x}{:02x}{:02x}".format(r, g, b)
# Меняем фон окна-предпросмотра
color_preview.configure(bg=current_color)
Важно: кисть у нас уже рисует цветом current_color, поэтому как только мы обновили эту переменную — следующая линия рисуется новым цветом автоматически. Никакой магии, просто переменная сменилась.
Маленькая донастройка: синхронизируем цвет сразу после создания интерфейса
После того как добавили ползунки и предпросмотр, инициализацию чуть дополняем: сразу после создания интерфейса вызываем update_color_from_sliders(), чтобы ползунки, переменная current_color, и окошко‑предпросмотр
сразу были в одном состоянии, а не “каждый сам по себе”.
# Сразу после создания интерфейса синхронизируем цвет
update_color_from_sliders()
"""Игровой цикл: пока running == True, окно живёт и реагирует на события."""
while running:
root.update() # Обрабатываются события: клик мыши, движение, закрытие окна
time.sleep(0.01) # Небольшая пауза для контроля количества кадров
Собираем всё вместе
Вот полная версия программы на этом этапе — уже с ползунками R/G/B и окошком текущего цвета, но без пипетки и кнопок толщины кисти. В следующем уроке мы сделаем выбор разной толщины кисти и кнопку чтобы всё стирать — часть 3.
!!ССЫЛКУ ВСТАВИТЬ В СЛОВО ЧАСТЬ 3!!

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
def create_color_scale(parent, name, column):
"""Создаёт один ползунок для компоненты цвета (R, G или B)."""
label = tk.Label(parent, text=name, fg="white", bg=orange_color)
label.grid(row=0, column=column)
scale = tk.Scale(
parent, # внутри какой рамки создаём
from_=0, # минимум
to=255, # максимум
orient="horizontal", # горизонтальный ползунок
length=200, # длина ползунка
command=lambda value: update_color_from_sliders(), # вызываем при изменении ползунка
showvalue=True, # показываем значение на ползунке
bg=orange_color, # фоновый цвет
fg="white",
troughcolor=purple_color, # задний фон ползунка
highlightthickness=0 # убираем белую рамку вокруг ползунка
)
scale.grid(row=1, column=column, padx=5)
return scale
def update_color_from_sliders():
"""Читает значения трёх ползунков и обновляет текущий цвет кисти."""
global current_color
r = int(r_scale.get())
g = int(g_scale.get())
b = int(b_scale.get())
# Собираем цвет в формате "#rrggbb"
current_color = "#{:02x}{:02x}{:02x}".format(r, g, b)
# Меняем фон окна-предпросмотра
color_preview.configure(bg=current_color)
# Главное окно программы
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)
# НИЗ: панель управления
controls_frame = tk.Frame(root, bg=orange_color)
controls_frame.pack(side="bottom", fill="x", padx=10, pady=(0, 10))
# Слева – три ползунка R, G, B
sliders_frame = tk.Frame(controls_frame, bg=orange_color)
sliders_frame.pack(side="left", padx=10)
r_scale = create_color_scale(sliders_frame, "R", 0)
g_scale = create_color_scale(sliders_frame, "G", 1)
b_scale = create_color_scale(sliders_frame, "B", 2)
# По центру – окно текущего цвета
preview_frame = tk.Frame(controls_frame, bg=orange_color)
preview_frame.pack(side="left", padx=20)
tk.Label(
preview_frame,
text="Текущий цвет",
fg="white",
bg=orange_color
).pack()
color_preview = tk.Canvas(
preview_frame,
width=80,
height=50,
bg=current_color,
)
color_preview.pack(pady=5)
update_color_from_sliders()
"""Игровой цикл: пока running == True, окно живёт и реагирует на события."""
while running:
root.update() # Обрабатываются события: клик мыши, движение, закрытие окна
time.sleep(0.01) # Небольшая пауза для контроля количества кадров
