Глава 18 · Инструменты рисования

Карандаш: непрерывный штрих

Отдельные кружки создают разрывы. Соединяем каждую точку с предыдущей — и штрих становится одной линией.

Почему кружки на каждое движение — плохая идея

Раздел 18.7 рисовал свободный штрих кружками — по одному на каждое событие <B1-Motion>. Работает, но у этого подхода есть три проблемы:

Реальный холст: штрих из отдельных кружков с заметными промежутками между ними
То же самое реальное окно из раздела 18.7: россыпь кружков вместо линии.

Лучшая модель: помнить предыдущую точку

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

karandash.py
def on_drag(self, event):
    self.canvas.create_line(
        self.state.last_x, self.state.last_y, event.x, event.y,
        fill=self.state.color, width=self.state.width,
        capstyle=tk.ROUND,
    )
    self.state.last_x, self.state.last_y = event.x, event.y
Отсюда код — это методы класса PaintApp
Начиная с этого раздела примеры пишутся как методы: def on_drag(self, event), self.state, self.canvas. Все они принадлежат классу PaintApp, который мы соберём целиком в разделе 18.29 — до тех пор достаточно читать self.state.color как «текущий цвет приложения».
Реальный холст: непрерывная плавная линия без разрывов, повторяющая движение мыши
Реальное окно финальной версии: та же самая рука, но линия без разрывов — потому что рисуются отрезки, а не отдельные точки.
ПараметрЗачем
capstyle=tk.ROUNDскругляет концы каждого отрезка — стыки между ними не выглядят «зубчатыми»
widthтолщина штриха; чем она больше, тем заметнее была бы «зубчатость» стыков без capstyle
А как же smooth=True? Здесь он не сработает
У create_line() есть параметр smooth=True — Tk сглаживает ломаную, проводя через её точки кривую. Но сглаживать он умеет только внутренние точки одной линии, а каждый наш отрезок состоит ровно из ДВУХ точек — между ними нет ни одного угла. Добавить smooth=True в этот код можно, и Tk его молча примет, но на экране не изменится ровно ничего. Параметр стал бы полезен, если бы весь штрих был ОДНОЙ длинной ломаной — такой вариант описан ниже.
Куда это можно развить: один штрих — одна ломаная
Сейчас каждое движение мыши создаёт отдельный элемент Canvas. Можно вместо этого создать линию один раз на <Button-1> и на каждом движении дописывать к ней новую пару координат через coords() (раздел 18.18): тогда длинный штрих — это один элемент вместо сотни, а smooth=True наконец получает внутренние точки, которые действительно можно сгладить. В этой главе оставлен более простой вариант с отдельными отрезками — он короче и его легче отлаживать.
Практика: непрерывный штрих карандаша
Модуль tkinter открывает нативное окно Python — выполните локально в VS Code, PyCharm или Jupyter
Практика выполняется локально
Открыть практику →