Создаем Paint с нуля за вечер №2: палитра R, G, B и окно текущего цвета

12.12.2025 

Время прочтения: 20 - 25 минут.

Что нас ждёт

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

gif1 - g2

Панель управления: где живут ползунки и предпросмотр цвета

Чтобы управлять цветом, добавим три ползунка снизу:

  • 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(). Она делает ровно две вещи:

  1. берёт значения трёх ползунков,

  2. собирает из них строку цвета вида "#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!!

gif2 - 2

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)     # Небольшая пауза для контроля количества кадров

Пробное занятие
с репетитором по математике и программированию

Запишитесь сейчас бесплатно 
Записаться

Понравилась статья?

Подпишись на Телеграм школы, чтобы не пропустить новые статьи и новости
Telegram канал