Рисование состоит из событий и сохранённых данных
Графическое приложение получает события: пользователь нажал кнопку мыши, переместил указатель, отпустил кнопку. Обработчик связывает событие с нужным действием. Для рисования важно знать не только текущие координаты, но и то, начат ли штрих. На холсте можно создавать линии по последовательности точек. В простейшей модели очередной отрезок соединяет предыдущую позицию с текущей. После этого текущая точка становится предыдущей для следующего движения. Но самая первая точка нового штриха ещё не имеет предшественника внутри этого штриха. Нажатие должно установить начало, а не проводить линию от произвольного старого места. Это различие удобно выразить отдельным состоянием кисти. Сначала опишите состояния словами: кисть не рисует и кисть рисует. Затем определите, какие события переводят её из одного состояния в другое.
Отпускание завершает связь между точками
Представим первый штрих: нажатие в точке с координатами десять и десять, затем движение к двадцати и двадцати. Получится один отрезок. После отпускания связь с предыдущей точкой должна завершиться. Новый штрих начинается в точке восемьдесят и десять и продолжается к девяноста и двадцати. Между концом первого и началом второго отрезка линии быть не должно. Если программа сохраняет старую точку как действующее начало, появляется лишняя перемычка. Для исправления полезно явно сбрасывать состояние при завершении штриха и заново задавать начальную точку при следующем нажатии. Не стоит рассчитывать, что большое расстояние между точками само подскажет программе намерение пользователя. Отдельно продумайте одиночное нажатие без движения. Если алгоритм создаёт только отрезки между двумя событиями, такая попытка может ничего не нарисовать. Нужное поведение точки следует определить отдельно.
Координаты и отмена требуют своего решения
Координаты события относятся к виджету. Если холст прокручивается, видимая область и координатная система содержимого могут различаться. Для такого случая у холста предусмотрено преобразование координат. В первом учебном варианте без прокрутки задача проще, но границу модели стоит обозначить. Для отмены также важно выбрать единицу действия. Один штрих может состоять из множества отрезков. Если удалять только последний созданный отрезок, пользователь получит не отмену всего движения, а маленькую поправку его конца. Поэтому заранее решите, как объединять части штриха: например, сохранять их как одну группу в собственной модели рисунка. Тогда история действий будет соответствовать тому, что воспринимает человек. Проверяйте несколько сценариев: два отдельных штриха, одиночное нажатие, движение без рисования и отмену последнего штриха. Эти случаи показывают поведение приложения лучше, чем один длинный непрерывный рисунок.
Попробуйте на практике
Проверьте модель кисти на бумажной последовательности событий.
- Запишите нажатие в точке десять, десять и движение к двадцати, двадцати. Нарисуйте получившийся отрезок и отметьте текущую точку.
- Добавьте отпускание. Покажите, что активного предыдущего положения для продолжения штриха больше нет.
- Запишите новое нажатие в точке восемьдесят, десять и движение к девяноста, двадцати. Нарисуйте второй отдельный отрезок.
- Проверьте отсутствие перемычки между штрихами. Затем опишите, что должна удалить команда отмены, если второй штрих состоит из нескольких отрезков.
Как проверить результат. Получены два независимых штриха. Нажатие задаёт новое начало, отпускание завершает состояние рисования, а отмена имеет заранее определённую единицу действия.
Частые вопросы
Достаточно ли хранить только текущие координаты мыши?
Для соединения точек нужны также предыдущая позиция и понимание, начат ли штрих. Иначе программа не различит продолжение линии и новое действие.
Отрезки на холсте и штрихи пользователя всегда одно и то же?
Нет. Штрих может быть представлен множеством объектов. Для удобной отмены и редактирования их связь нужно сохранить в логике приложения.
Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.