Статьи Королевства Дельфи


Программа Canvas2


Если вы честно прочитали всё, что написано выше, и не поленились посмотреть в MSDN'е описание упомянутых в тексте функций, вы уже можете самостоятельно написать программу, подобную Canvas2. Правда, новичков нередко ставит в тупик задача создания "резиновой" линии, особенно кривой, которую потом можно изменять. Однако эта задача не требует ни каких-либо специальных знаний, ни особого напряжения интеллекта. Достаточно просто набраться терпения, просчитать все возможные состояния процесса и описать реакцию на все эти состояния в программе.

Начиная с этого момента я предполагаю, что вы уже успели попробовать Canvas2 и поэтому хорошо представляете процесс рисования кривых с её помощью.

Итак, у нас есть два основных состояния: когда рисование кривой ещё не начато, и нажатие левой кнопки мыши приведёт к появлению "резиновой" прямой, которая затем станет основой для кривой, и когда кривая уже нарисована, но ещё не "впечатана" в рисунок, т.е. её крайние и промежуточные точки можно передвигать. Переменная TCurveForm.NewLine типа Boolean указывает, в каком из двух состояний находится программа: в первом (True) или во втором (False).

Когда пользователь схватил точку и тащит её, возможно шесть вариантов: схвачена одна из четырёх контрольных точек редактируемой кривой, рисуется "резиновая" прямая или при редактировании кривой пользователь промахнулся и не схватил ни одной из контрольных точек. Для описания того, какая точка сейчас перемещается пользователем, объявлена переменная TCurveForm.DragPoint специально созданного типа TDragPoint. Эта переменная может иметь следующие значения:

  • ptNone - пользователь пытается тянуть несуществующую точку
  • ptFirst - пользователь перемещает вторую точку "резиновой" прямой
  • ptBegin - пользователь перемещает начало кривой
  • ptInter1, ptInter2 - пользователь перемещает промежуточные точки
  • ptEnd - пользователь перемещает конец кривой

Для хранения координат кривой используется массив TCurveForm.Curve. Его нулевой элемент хранит начало прямой, третий - её конец, а первый и второй - промежуточные точки. В режиме "резиновой" прямой первый и второй элементы не используются, поэтому они могут иметь произвольные значения.

Процедура OnPaint должна учитывать состояние программы: до редактирования кривой ещё не дошло (NewLine=True), нужно проверить, не перемещает ли пользователь концевую точку прямой, и если да, нарисовать эту прямую. Если редоктирование кривой уже начато, надо отобразить кривую и дополнительные элементы для редактирования (касательные и маркеры контрольных точек).

Когда пользователь нажимает кнопку мыши, программа должна проверить, в каком состоянии находится программа. Если редактирование кривой ещё не начато, это нажатие означает начало рисования "резиновой" прямой. Для перехода в этот режим значение DragPoint устанавливается в dpFirst. Если редактирование кривой уже начато, необходимо проверить, попадает ли позиция курсора мыши в окрестность какой-либо контрольной точки, и на основании результатов проверки присвоить соответствующее значение переменной DragPoint. Для проверки определена функция PtNearPt. Строго говоря, необходимо также запоминать, насколько отстоят координаты курсора мыши от координат контрольной точки, чтобы при первом перемещении не было скачка. Но так как окрестность точки очень мала, этот прыжок практически незаметен, и в данном случае этим можно пренебречь, чтобы не усложнять программу.

При перемещении мыши нужно проверить, нажата ли левая кнопка и перемещает ли пользователь какую-либо точку. Если да, требуется обновить координаты этой точки и перерисовать окно.

При отпускании пользователем кнопки мыши какие-либо действия требуются, только если до этого был установлен режим "резиновой" прямой. В этом случае нужно вычислить координаты промежуточных точек (они выбираются на прямой) и перейти в режим редактирования кривой.

Нажатие кнопки "Завершить" осуществляет выход из режима редактирования кривой. Кривая переносится на растр TCurveForm.Back, а значение NewLine снова устанавливается в True.

Функция рисования кривой достаточно проста. Сначала рассчитываются координаты опорных точек. Если включен режим рисования по опорным точкам, координаты этих точек хранятся в первом и втором элементах массива Curve. Если включен режим рисования по промежуточным точкам, координаты опорных точек вычисляются по формулам (2). Затем на основе кривой создаётся траектория, затем она преобразуется в ломаную, и координаты её узлов записываются в массив PtBuf. В массив TpBuf записываются типы точек, но в данном случае они нам неинтересны: траектория содержит только один контур, состоящий только из отрезков прямых. Далее последовательно вызывается функция LineDDA для каждого из отрезков. При этом вычисляется длина отрезка и смещения координат DX и DY. Это нужно для построения поперечных линий. Как показала практика, начало и конец отрезка иногда совпадают, и его длина равна нулю, поэтому нужна дополнительная проверка, позволяющая избежать деления на ноль.

Функция LineDDA передаёт в вызываемую ею LineDrawFunc один дополнительный параметр, который использован для передачи объекта холста (Canvas), на котором следует рисовать отрезок. Этот параметр в соответствии с описанием функции является целым числом, но контроль типов здесь отсутствует, поэтому можно использовать любую 32-разрадную величину. Так как все переменные объектов в Delphi являются 32-разрядными указателями, объект TCanvas может быть передан в качестве этого параметра. Функция LineDDA не считает точки, поэтому это приходится делать самостоятельно с помощью переменной TCurveForm.Counter. Так как значение этой переменной между рисованием отдельных ломаных не меняется, кривая имеет целостный вид.

Функция LineDrawFunc достаточно проста для понимания. В некотором комментарии нуждается только выбор толщины пера при рисовании стилем "плакатное перо". Предположим, некоторая точка прямой имеет координаты (X,Y), а соседняя с ней - координаты (X+1,Y-1). Тогда при проведении через эти точки наклонной линии одинарной ширины между ними останутся незаполненные точки, как на шахматной доске. Поэтому потребовалось увеличить толщину пера.

Надеюсь, изложенные здесь материал оказался вам полезным
С пожеланиями творческих успехов


Специально для

Скачать (170K)

Для данного материала нет комментариев.




Начало  Назад  Вперед