Чтение онлайн

ЖАНРЫ

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

 begin

Arrow[I].X := ClientWidth - ArrowOffset - 1 - ArrowTemplate[I].X;

Arrow[I].Y := ArrowTemplate[I].Y + ArrowOffset;

 end;

 if ArrowTopRight <> 0 then DeleteObject(ArrowTopRight);

 ArrowTopRight := CreatePolygonRgn(Arrow[0], Length(Arrow), WINDING);

 // Вычисление региона левой нижней стрелки

 // Координаты по Y отражаются и смещаются

 // на постоянную величину относительно нижнего края окна

 for I := 0 to High(Arrow) do

 begin

Arrow[I].X := ArrowTemplate[I].X + ArrowOffset;

Arrow[I].Y := ClientHeight - ArrowOffset - 1 - ArrowTemplate[I].Y;

 end;

 if ArrowBottomLeft <> 0 then DeleteObject(ArrowBottomLeft);

 ArrowBottomLeft := CreatePolygonRgn(Arrow[0], Length(Arrow), WINDING);

 //
Вычисление региона правой нижней стрелки

 // Координаты по обеим осям отражаются и смещаются

 // на постоянную величину относительно правого нижнего угла окна

 for I := 0 to High(Arrow) do

 begin

Arrow[I].X := ClientWidth - ArrowOffset - 1 - ArrowTemplate[I].X;

Arrow[I].Y := ClientHeight - ArrowOffset - 1 - ArrowTemplate[I].Y;

 end;

 if ArrowBottomRight <> 0 then DeleteObject(ArrowBottomRight);

 ArrowBottomRight := CreatePolygonRgn(Arrow[0], Length(Arrow), WINDING);

end;

Следующий шаг — рисование стрелки на форме. Делается это очень просто (листинг 1.56).

Листинг 1.56. Рисование стрелок на форме

procedure TFormHole.FormPaint(Sender: TObject);

begin

 // Закрашиваем регионы стрелок

 Canvas.Brush.Style := bsSolid;

 Canvas.Brush.Color := clRed;

 FillRgn(Canvas.Handle, ArrowTopLeft, Canvas.Brush.Handle);

 FillRgn(Canvas.Handle, ArrowTopRight, Canvas.Brush.Handle);

 FillRgn(Canvas.Handle, ArrowBottomLeft, Canvas.Brush.Handle);

 FillRgn(Canvas.Handle, ArrowBottomRight, Canvas.Brush.Handle);

Остался последний шаг — объяснить системе, что пользователь может, ухватив за стрелки, изменять размеры формы. Очевидно, что делается это через обработчик

WM_NCHITTEST
. Вопрос только в том, как узнать, когда координаты мыши попадают внутрь нарисованной стрелки, поскольку стрелка является объектом сложной формы, вычислить это не очень просто. Данная задача также решается с помощью регионов: попадание координат курсора в регион каждой из стрелок отслеживается с помощью стандартной функции
PtInRegion
(листинг 1.57).

Листинг 1.57. Обработчик
WM_NCHITTEST
формы

procedure TFormHole.WMNCHitTest(var Msg: TWMNCHitTest);

var

 Pt: TPoint;

begin

 // Чтобы правильно обрабатывать стандартную неклиентскую область,

 // вызываем унаследованный обработчик

 inherited;

 // Не забываем, что параметры WM_NCHITTEST дают экранные,

 //
а не клиентские координаты

 Pt := ScreenToClient(Point(Msg.XPos, Msg.YPos));

 // Проверяем координаты на попадание в регионы стрелок

 if PtInRegion(ArrowTopLeft, Pt.X, Pt.Y) then

Msg.Result := HTTOPLEFT

 else if PtInRegion(ArrowTopRight, Pt.X, Pt.Y) then

Msg.Result := HTTOPRIGHT

 else

if PtInRegion(ArrowBottomLeft, Pt.X, Pt.Y) then

Msg.Result := HTBOTTOMLEFT

else

if PtInRegion(ArrowBottomRight, Pt.X, Pt.Y) then

Msg.Result := HTBOTTOMRIGHT;

end;

Вот и все. С помощью нескольких нехитрых приемов мы получили окно, которое имеет такой необычный вид (см. рис. 1.14).

1.3.4. Обобщающий пример 4 — Линии нестандартного стиля

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

1.3.4.1. Получение координат точек прямой

Рисование нестандартных линий выполняется следующим образом: вычисляются координаты всех пикселов, составляющих данную прямую, а потом каждый из них (а при необходимости — и какая-либо его окрестность) раскрашиваются нужным цветом. Следовательно, возникает вопрос об определении координат пикселов.

Существует ряд алгоритмов вычисления этих координат. Наиболее известный из них — алгоритм Брезенхэма (Bresengham), который заключается в равномерном разбрасывании "ступенек" разной длины вдоль линии. В Windows используется алгоритм GIQ (Grid Intersection Quantization). Каждый пиксел окружается воображаемым ромбом из четырех пикселов. Если прямая имеет общие точки с этим ромбом, то пиксел рисуется.

Самостоятельно реализовывать один из таких алгоритмов нет необходимости — в Windows существует функция

LineDDA
, которая возвращает вызвавшей ее программе координаты линии. Эта функция в качестве параметра принимает координаты начала и конца линии, а также указатель на функцию, которой будут передаваться координаты пикселов. Данная функция должна быть реализована в программе. За время выполнения
LineDDA
эта функция будет вызвана столько раз, сколько пикселов содержит линия (как обычно в Windows, последний пиксел не считается принадлежащим прямой). Каждый раз при вызове ей будут передаваться координаты очередного пиксела, причем пикселы будут упорядочены от начала к концу прямой.

В примере Lines (рис. 1.15) с помощью

LineDDA
рисуется пять различных типов линий. Рассмотрим на примере самого сложного из реализуемых программой типов линии ("Зеленая елочка"), как это делается (листинг 1.58).

Рис. 1.15. Окно программы Lines

Листинг 1.58. Рисование линии сложного стиля

// константы для типа "Зеленая елочка"

const

 // Угол отклонения "иголки" от направления линии

Поделиться с друзьями: