Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_I.pdf
Скачиваний:
96
Добавлен:
05.06.2014
Размер:
4.61 Mб
Скачать

117

Создание и рисование регионов

Регион — это описание области дисплея, состоящей из комбинации прямоугольников, многоугольников и эллипсов. Вы можете использовать регионы для рисования или для отсечения. Регион для отсечения, другими словами, ограничения рисования в заданной области рабочей зоны выбирается в контекст устройства. Регионы, так же как перья, кисти и битовые образы тоже являются объектами GDI. Любой регион, созданный вами ранее, следует удалять с помощью функции DeleteObject.

Когда вы создаете регион, Windows возвращает описатель региона, имеющий тип HRGN. Простейший тип региона

— это прямоугольник. Вы можете создать прямоугольный регион одним из двух способов:

hRgn = CreateRectRgn(xLeft, yTop, xRight, yBottom);

или

hRgn = CreateRectRgnIndirect(&rect);

Вы можете также создать эллиптические регионы, используя:

hRgn = CreateEllipticRgn(xLeft, yTop, xRight, yBottom);

или

hRgn = CreateEllipticRgnIndirect(&rect);

Функция CreateRoundRectRgn строит прямоугольный регион со скругленными углами. Создание многоугольного региона похоже на использование функции Polygon:

hRgn = CreatePolygonRgn(&point, iCount, iPolyFillMode);

Параметр point — это массив структур типа POINT, iCount — число точек, iPolyFillMode — равен либо ALTERNATE, либо WINDING. Вы можете также создать регион из множества многоугольников, используя функцию CreatePolyPolygonRgn.

Вы спросите: "Ну и что?" Что особенного делают эти регионы? Ниже приведена функция, которая иллюстрирует возможности регионов:

iRgnType = CombineRgn(hDestRgn, hSrcRgn1, hSrcRgn2, iCombine);

Она комбинирует два исходных региона (hSrcRgn1 и hSrcRgn2) и строит третий, на который ссылается hDestRgn. Все три описателя регионов еще до вызова функции должны быть действительными, однако дополнительный регион, описываемый ранее hDestRgn, уничтожается. (Когда вы используете эту функцию, вы можете сначала сделать так, чтобы hDestRgn ссылался на маленький прямоугольный регион.)

Параметр iCombine описывает, как объединяются 2 региона с описателями hSrcRgn1 и hSrcrgn2:

Значение iCombine

Новый регион

RGN_AND

Область пересечения двух исходных регионов

RGN_OR

Объединение двух исходных регионов

RGN_XOR

Объединение двух исходных регионов за исключением

 

области пересечения

RGN_DIFF

Часть региона hSrcRgn1, не входящая в регион hSrcRg2

RGN_COPY

Регион hSrcRgn1

Величина iRgnType, возвращаемая от функции CombineRect, принимает одно из следующих значений: NULLREGION, показывающее, что регион пуст; SIMPLEREGION, показывающее, что регион представляет собой простой прямоугольник, эллипс или многоугольник; COMPLEXREGION, показывающее, что регион представляет собой комбинацию прямоугольников, эллипсов или многоугольников; ERROR, означающее, что произошла ошибка.

Получив описатель региона, вы можете использовать его в следующих четырех функциях рисования:

FillRgn(hdc, hRgn, hBrush);

FrameRgn(hdc, hRgn, hBrush, xFrame, yFrame);

InvertRgn(hdc, hRgn);

PaintRgn(hdc, hRgn);

Функции FillRgn, FrameRgn и InvertRgn похожи на функции FillRect, FrameRect и InvertRect. Параметры xFrame и yFrame функции FrameRect — это логические ширина и высота рамки, которая будет нарисована вокруг региона. Функция PaintRgn закрашивает внутреннюю область региона текущей выбранной в контекст устройства кистью. Во всех этих функциях предполагается, что регион определен в логических координатах.

118

Когда вы заканчиваете работу с регионом, вы можете его удалить, используя ту же самую функцию DeleteObject, что и для удаления других объектов GDI:

DeleteObject(hRgn);

Отсечения: прямоугольники и регионы

Регионы также могут принимать участие в отсечении. Функция InvalidateRect делает недействительным прямоугольную область дисплея и генерирует сообщение WM_PAINT. Например, вы можете использовать функцию InvalidateRect для обновления рабочей области и генерации сообщения WM_PAINT:

InvalidateRect(hwnd, NULL, TRUE);

Вы можете получить координаты недействительного прямоугольника, вызвав функцию GetUpdateRect, и вы можете сделать действительным прямоугольник в рабочей области, используя функцию ValidateRect. Когда вы получаете сообщение WM_PAINT, координаты недействительного прямоугольника доступны из полей структуры PAINTSTRUCT, которые заполняются при вызове функции BeginPaint. Этот недействительный прямоугольник также определяет "регион отсечения". Вы не можете рисовать за пределами региона отсечения.

Windows содержит две функции, похожие на InvalidateRect и ValidateRect, работающие с регионами, а не с прямоугольниками:

InvalidateRgn(hwnd, hRgn, bErase);

и

ValidateRgn(hwnd, hRgn);

Когда вы получаете сообщение WM_PAINT как результат того, что регион стал недействительным, регион отсечения не обязательно будет прямоугольным.

Вы можете создать свой собственный регион отсечения, выбрав регион в контекст устройства и используя одну из двух функций:

SelectObject(hdc, hRgn);

или

SelectClipRgn(hdc, hRgn);

Регион отсечения задается в координатах устройства.

GDI делает копию региона отсечения, поэтому вы можете удалить объект-регион после выбора его в контекст устройства. Windows содержит также несколько функций для манипуляций с регионом отсечения, таких как ExcludeClipRect для исключения прямоугольника из региона отсечения, IntersectClipRect для создания нового региона отсечения, который представляет собой пересечение предыдущего региона отсечения и прямоугольника, и OffsetClipRgn для перемещения региона отсечения в другую часть рабочей области.

Программа CLOVER

Программа CLOVER формирует регион, состоящий из четырех эллипсов, выбирает этот регион в контекст устройства, а затем рисует набор линий, исходящих из центра рабочей области окна. Линии будут отображаться только в области, определенной регионом. Результат работы программы приведен на рис. 4.22.

Рис. 4.22 Вывод программы CLOVER, нарисованный с использованием сложного региона отсечения

119

Для того, чтобы нарисовать такой рисунок традиционными методами, вам пришлось бы вычислять конечные точки для каждой прямой по формулам для расчета кривой эллипса. Используя сложный регион отсечения, вы можете рисовать линии и оставить Windows расчеты конечных точек. Программа CLOVER приведена на рис. 4.23.

CLOVER.MAK

#----------------------

# CLOVER.MAK make file

#----------------------

clover.exe : clover.obj

$(LINKER) $(GUIFLAGS) -OUT:clover.exe clover.obj $(GUILIBS)

clover.obj : clover.c

$(CC) $(CFLAGS) clover.c

CLOVER.C

/*--------------------------------------------------

CLOVER.C -- Clover Drawing Program using Regions

(c) Charles Petzold, 1996

--------------------------------------------------*/

#include <windows.h> #include <math.h>

#define TWO_PI(2.0 * 3.14159)

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{

static char szAppName[] = "Clover";

HWND

hwnd;

MSG

msg;

WNDCLASSEX

wndclass;

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= WndProc;

wndclass.cbClsExtra

= 0;

wndclass.cbWndExtra

= 0;

wndclass.hInstance

= hInstance;

wndclass.hIcon

= LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor

= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground

=(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName

= NULL;

wndclass.lpszClassName

= szAppName;

wndclass.hIconSm

= LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);

hwnd = CreateWindow(szAppName, "Draw a Clover", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

120

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

static HRGN hRgnClip;

static int

cxClient, cyClient;

double

fAngle, fRadius;

HCURSOR

hCursor;

HDC

hdc;

HRGN

hRgnTemp[6];

int

i;

PAINTSTRUCT

ps;

switch(iMsg)

{

case WM_SIZE:

cxClient = LOWORD(lParam); cyClient = HIWORD(lParam);

hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

ShowCursor(TRUE);

if(hRgnClip)

DeleteObject(hRgnClip);

hRgnTemp[0] = CreateEllipticRgn(0, cyClient / 3,

cxClient / 2, 2 * cyClient / 3);

hRgnTemp[1] = CreateEllipticRgn(cxClient / 2, cyClient / 3,

cxClient, 2 * cyClient / 3); hRgnTemp[2] = CreateEllipticRgn(cxClient / 3, 0,

2 * cxClient / 3, cyClient / 2);

hRgnTemp[3] = CreateEllipticRgn(cxClient / 3, cyClient / 2,

2 * cxClient / 3, cyClient);

hRgnTemp[4] = CreateRectRgn(0, 0, 1,

1);

hRgnTemp[5] = CreateRectRgn(0, 0, 1,

1);

hRgnClip

= CreateRectRgn(0, 0, 1,

1);

CombineRgn(hRgnTemp[4], hRgnTemp[0],

hRgnTemp[1], RGN_OR);

CombineRgn(hRgnTemp[5], hRgnTemp[2],

hRgnTemp[3], RGN_OR);

CombineRgn(hRgnClip,

hRgnTemp[4],

hRgnTemp[5], RGN_XOR);

for(i = 0; i < 6; i++) DeleteObject(hRgnTemp[i]);

SetCursor(hCursor);

ShowCursor(FALSE); return 0;

case WM_PAINT:

hdc = BeginPaint(hwnd, &ps);

SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);

SelectClipRgn(hdc, hRgnClip);

fRadius = _hypot(cxClient / 2.0, cyClient / 2.0);

for(fAngle = 0.0; fAngle < TWO_PI; fAngle += TWO_PI / 360)

{

MoveToEx(hdc, 0, 0, NULL);

LineTo(hdc,(int)( fRadius * cos(fAngle) + 0.5), (int)(-fRadius * sin(fAngle) + 0.5));

}

Соседние файлы в предмете Операционные системы