// будут смещаться и отражаться
const
ArrowTemplate: TArrowCoords = (
(X:0; Y:0), (X:24; Y:0), (X:17; Y:7), (X:29; Y:19),
(X:19; Y:29), (X:7; Y:17), (X:0; Y:24));
procedure TFomHole.CalculateArrows;
var
Arrow: TArrowCoords;
I: Integer;
begin
// Вычисление региона левой верхней стрелки
// Координаты просто смещаются на постоянную величину
for I := 0 to High(Arrow) do
begin
Arrow[I].X := ArrowTemplate[I].X + ArrowOffset;
Arrow[I].Y := ArrowTemplate[I].Y + ArrowOffset;
end;
// При необходимости уничтожаем старый регион
if ArrowTopLeft <> 0 then DeleteObject(ArrowTopLeft);
ArrowTopLeft :=
CreatePolygonRgn(Arrow[0], Length(Arrow), WINDING);
// Вычисление региона правой верхней стрелки
// Координаты по X отражаются и смещаются
// на постоянную величину относительно правого края окна
for I := 0 to High(Arrow) do
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. Получение координат точек прямой
Рисование нестандартных линий выполняется следующим образом: вычисляются координаты всех пикселов, составляющих данную прямую, а потом каждый из них (а при необходимости — и какая-либо его окрестность) раскрашиваются нужным цветом. Следовательно, возникает вопрос об определении координат пикселов.
Читать дальше
Конец ознакомительного отрывка
Купить книгу