1.3.4.2. "Резиновая" линия и растровые операции

1.3.4.2. "Резиновая" линия и растровые операции

Теперь нужно дать пользователю возможность рисовать линии. Для этого мы используем стандартную "резиновую" линию: пользователь нажимает левую кнопку мыши и, удерживая ее, передвигает мышь. До тех пор, пока кнопка удерживается, за курсором тянется линия. Как только пользователь отпускает кнопку, линия "впечатывается" в рисунок.

Сама по себе реализация "резиновой" линии очень проста: при наступлении события OnMouseDown запоминаются координаты начала линии и взводится флаг, показывающий, что включен режим рисования "резиновой" линии. Также запоминаются координаты конца отрезка, который на данный момент совпадает с началом. В обработчике OnMouseMove, если включен режим рисования "резиновой" линии, стирается линия со старыми координатами конца и рисуется с новыми. При наступлении OnMouseUp программа выходит из режима рисования "резиновой" линии, рисуя окончательный ее вариант с текущими координатами конца.

Самое сложное в этой последовательности действий — стереть нарисованную ранее линию. Если бы у нас был однородный фон, можно было бы просто нарисовать старую линию еще раз цветом фона — это выглядело бы как ее стирание. Но поскольку фон не однородный, а составлен из нарисованных ранее линий, этот способ мы применить не можем.

Для решения этой задачи мы здесь рассмотрим самый простой метод — инверсное рисование (более сложный метод будет рассмотрен чуть позже). При этом каждая точка, принадлежащая линии, закрашивается не каким-либо фиксированным цветом, а инвертируется (т. е. к текущему цвету точки применяется операция not). Для стирания линии просто рисуем ее еще раз: двойная инверсия восстанавливает предыдущий цвет точек (not not X = X для любого X).

При рисовании пером и кистью GDI позволяет использовать различные растровые операции, которые определяют результирующий цвет каждого пиксела в зависимости от цвета фона и пера или кисти. По умолчанию применяется операция R2_COPYPEN, в которой цвет фона игнорируется, а результирующий цвет пиксела совпадает с цветом пера или кисти. Изменить растровую операцию можно с помощью функции SetROP2 (двойка в названии функции показывает, что устанавливаемая растровая операция имеет два аргумента — цвет рисования и цвет фона: при выводе растровых рисунков могут применяться растровые операции с тремя аргументами — см. функцию BitBlt). Нас будет интересовать операция R2_NOT, которая инвертирует фоновый цвет, игнорируя цвет пера или кисти.

Примечание

Растровая операция влияет на все, что рисуется с помощью пера и кисти, т. е. на рисование границ фигур и их заливку. Кроме того, растровая операция влияет также на результат работы функции SetPixel (и, соответственно, изменение цвета с помощью Canvas.Pixels[X, Y]), т. к. эта операция выполняется с мощью кистей.

Код, рисующий "резиновую" линию, приведен в листинге 1.59.

Листинг 1.59. Рисование "резиновой" линии инверсным методом

procedure TLinesForm.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

begin

 if Button = mbLeft then begin

 OldX:= X;

 OldY:= Y;

 BegX:= X;

 BegY:= Y;

LineDrawing:= True;

 end;

end;

procedure TLinesForm.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);

begin

 if LineDrawing and ((X <> OldX) or (Y <> OldY)) then

 with Canvas do

 begin

SetROP2(Handle, R2_NOT);

Line(BegX, BegY, OldX, OldY); // Стираем старую линию.

Line(BegX, BegY, X, Y); // Рисуем новую.

OldX:= X;

OldY:= Y;

 end;

end;

procedure TLinesFom.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

begin

 if (Button = mbLeft) and LineDrawing then

 begin

case RGroupLine.ItemIndex of

 2: Canvas.Pen.Color:= clBlue;

3: begin

Canvas.Brush.Color:= clRed;

Canvas.Pen.Color:= clRed;

 end;

4: Canvas.Pen.Color:= clGreen;

end;

Line(BegX, BegY, X, Y);

LineDrawing:= False;

 end;

end;

Обратите внимание, что резиновая линия следует за мышью даже тогда, когда мышь выходит за пределы формы, т. е. форма получает сообщения мыши, когда курсор находится за ее пределами. Это становится возможным благодаря захвату мыши окном. Любое окно в Windows может захватить мышь для монопольного использования, и тогда все сообщения от мыши будет получать это окно, независимо от того, где находится курсор. В VCL любой визуальный компонент, у которого установлен стиль csCaptureMouse (а у формы он по умолчанию установлен) автоматически захватывает мышь при нажатии левой кнопки и освобождает при ее отпускании, поэтому мы получаем требуемый нам эффект автоматически.

Данный текст является ознакомительным фрагментом.