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

121

EndPaint(hwnd, &ps); return 0;

case WM_DESTROY: DeleteObject(hRgnClip); PostQuitMessage(0); return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

Рис. 4.23 Программа CLOVER

Поскольку регионы всегда используют координаты устройства, программа CLOVER должна перестраивать регион каждый раз при получении сообщения WM_SIZE. Это может занять несколько секунд. Программа начинает работу, создавая четыре эллиптических региона, которые запоминаются в первых четырех элементах массива hRgnTemp. Затем программа строит три фиктивных региона:

hRgnTemp [4] = CreateRectRgn(0, 0, 1, 1); hRgnTemp [5] = CreateRectRgn(0, 0, 1, 1); hRgnClip = CreateRectRgn(0, 0, 1, 1);

Затем комбинируются два эллиптических региона слева и справа рабочей области:

CombineRgn(hRgnTem[4], hRgnTemp[0], hRgnTemp[1], RGN_OR);

Затем аналогично комбинируются два эллиптических региона сверху и снизу рабочей области:

CombineRgn(hRgnTem[5], hRgnTemp[2], hRgnTemp[3], RGN_OR);

Окончательно, эти два комбинированных региона объединяются в hRgnClip:

CombineRgn(hRgnClip, hRgnTemp[4], hRgnTemp[5], RGN_XOR);

Идентификатор RGN_XOR используется для исключения области пересечения из результирующего региона. Затем, все шесть временных регионов удаляются:

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

Обработка сообщения WM_PAINT проста, принимая во внимание результаты. Начало координат области вывода (viewport) устанавливается в центр рабочей зоны (чтобы сделать рисование линий более простым), и регион, созданный при обработке сообщения WM_CREATE, выбирается в контекст устройства в качестве региона отсечения:

SetViewportOrg(hdc, xClient / 2, yClient / 2);

SelectClipRgn(hdc, hRgnClip);

Теперь осталось только нарисовать линии — 360 штук, отстоящих друг от друга на один градус. Длина каждой линии — переменная fRadius, задается равной расстоянию от центра до угла рабочей области:

fRadius = _hypot(xClient / 2.0, yClient / 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));

}

При обработке сообщения WM_DESTROY регион удаляется:

DeleteObject(hRgnClip);

Пути

Путь — это набор прямых линий и кривых, хранящийся внутри GDI. Пути (paths) были введены в Windows в версии Windows NT. Они также поддерживаются и в Windows 95. На первый взгляд пути и регионы могут показаться очень похожими, и, в самом деле, вы можете конвертировать путь в регион и использовать путь для отсечения. Тем не менее, мы рассмотрим их отличия.

Создание и воспроизведение путей

Для того, чтобы начать определение пути, вы просто вызываете функцию:

122

BeginPath(hdc);

После этого вызова любая рисуемая вами линия (прямая, дуга или сплайн Безье) будет запоминаться внутри GDI как часть пути и не будет воспроизводиться в контексте устройства. Часто пути состоят из связанных друг с другом линий. Для создания связанных линий вы используете функции LineTo, PolylineTo и BezierTo, каждая из которых рисует линию, начинающуюся из текущего положения пера. Если вы изменяете текущее положение пера, используя функцию MoveToEx, или если вы вызываете какую-либо другую функцию рисования линии, или если вы вызываете одну из функций окна или области вывода, влияющих на изменение текущего положения пера, то вы создаете новый подпуть в рамках пути. Таким образом, путь состоит из одного или нескольких подпутей, причем каждый подпуть — это серия связанных линий.

Каждый подпуть в рамках пути может быть открыт или закрыт. Подпуть закрыт, если в нем первая точка первой связанной линии и последняя точка последней связанной линии совпадают. Подпуть закрывается вызовом функции CloseFigure. Эта функция закрывает подпуть, добавляя, если необходимо, прямую линию. Любой последующий вызов функции рисования начинает новый подпуть. В конце вы завершаете определение пути, вызывая функцию:

EndPath(hdc);

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

StrokePath(hdc);

FillPath(hdc);

StrokeAndFillPath(hdc);

hRgn = PathToRegion(hdc);

SelectClipPath(hdc, iCombine);

Любая из этих функций уничтожает определение пути после завершения.

StrokePath рисует путь, используя текущее перо. Вы можете удивиться: в чем смысл? Почему нельзя пропустить все эти штучки с путем, и нарисовать линии нормально? Ответ вы получите очень скоро.

Другие четыре функции закрывают все открытые пути прямыми линиями. Функция FillPath закрашивает путь, используя текущую кисть, в соответствии с текущим режимом закрашивания многоугольников. Функция StrokeAndFillPath выполняет оба указанных действия. Вы можете также преобразовать путь в регион или использовать путь как область отсечения. Параметр iCombine — одна из RGN-констант, используемых в функции CombineRgn, и показывает, как путь должен комбинироваться с текущим регионом отсечения.

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

Расширенные перья

Когда вы вызываете StrokePath, путь воспроизводится с использованием текущего пера. Ранее в этой главе рассматривалась функция CreatePen, которая используется для создания объекта "перо". Одновременно с поддержкой путей в Windows NT и Windows 95 введена расширенная функция пера, называемая ExtCreatePen, она применяется, когда бывает удобнее создать сглаженный путь, чем рисовать линии без использования пути. Функция ExtCreatePen выглядит так:

hPen = ExtCreatePen(iStyle, iWidth, &lBrush, 0, NULL);

Вы можете использовать эту функцию для обычного рисования линий, но в таком случае некоторые из возможностей не реализуются в Windows 95. Даже при воспроизведении путей с ее помощью остаются параметры, которые так и не поддерживаются Windows 95, что показано выше, когда два последних параметра заданы равными 0 и NULL.

Для первого параметра функции ExtCreatePen вы можете использовать любой из стилей, описанных ранее для функции CreatePen. Кроме того, вы можете комбинировать эти стили со стилем PS_GEOMETRIC (при этом параметр iWidth означает ширину линии в логических единицах измерения для преобразования) или PS_COSMETIC (при этом параметр iWidth должен быть равен 1). В Windows 95 точечные и штриховые перья должны иметь стиль PS_COSMETIC. (Это ограничение отсутствует в Windows NT.)

Одним из параметров функции CreatePen является цвет; однако, функция ExtCreatePen для задания цвета пера стиля PS_GEOMETRIC использует кисть. Такие кисти могут быть определены как битовые образы.

Когда вы рисуете широкие линии, вас, вероятно, интересует то, как будут представлены концы линий. Когда прямые или кривые соединены, вас может также заинтересовать то, как будут представлены места соединения линий. При использовании перьев, созданных функцией CreatePen, эти концы и места соединения всегда будут скругленными. При работе с перьями, созданными функцией ExtCreatePen, у вас есть выбор. (В действительности

123

в Windows 95 такая возможность существует только при сглаживании пути; Windows NT обладает большей гибкостью.) Представление концов линий может быть задано путем применения в функции ExtCreatePen один из следующих стилей пера:

PS_ENDCAP_ROUND

PS_ENDCAP_SQUARE

PS_ENDCAP_FLAT

Аналогично, места соединения линий в пути могут быть заданы так:

PS_JOIN_ROUND

PS_JOIN_BEVEL

PS_JOIN_MITER

Стиль "bevel" отрезает конец места соединения, а стиль "miter" заостряет его. Это лучше всего иллюстрируется программой ENDJOIN, приведенной на рис. 4.24.

ENDJOIN.MAK

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

# ENDJOIN.MAK make file

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

endjoin.exe : endjoin.obj

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

endjoin.obj : endjoin.c

$(CC) $(CFLAGS) endjoin.c

ENDJOIN.C

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

ENDJOIN.C -- Ends and Joins Demo

(c) Charles Petzold, 1996

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

#include <windows.h>

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

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

{

static char szAppName[] = "EndJoin";

HWND

hwnd;

MSG

msg;

WNDCLASSEX

wndclass;

wndclass.cbSize

= sizeof(WNDCLASSEX);

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, "Ends and Joins Demo", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

124

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

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

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

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

{

 

static int

iEnd [] = { PS_ENDCAP_ROUND, PS_ENDCAP_SQUARE,

 

PS_ENDCAP_FLAT };

static int

iJoin [] = { PS_JOIN_ROUND, PS_JOIN_BEVEL,

 

PS_JOIN_MITER };

static int

cxClient, cyClient;

HDC

hdc;

int

i;

LOGBRUSH

lb;

PAINTSTRUCT

ps;

switch(iMsg)

{

case WM_SIZE:

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

case WM_PAINT:

hdc = BeginPaint(hwnd, &ps);

SetMapMode(hdc, MM_ANISOTROPIC);

SetWindowExtEx(hdc, 100, 100, NULL);

SetViewportExtEx(hdc, cxClient, cyClient, NULL);

lb.lbStyle = BS_SOLID; lb.lbColor = RGB(128, 128, 128); lb.lbHatch = 0;

for(i = 0; i < 3; i++)

{

SelectObject(hdc,

ExtCreatePen(PS_SOLID | PS_GEOMETRIC | iEnd [i] | iJoin [i], 10, &lb, 0, NULL));

BeginPath(hdc);

MoveToEx(hdc, 10 + 30 * i, 25, NULL);

LineTo (hdc, 20 + 30 * i, 75);

LineTo (hdc, 30 + 30 * i, 25);

EndPath(hdc);

StrokePath(hdc);

DeleteObject(

SelectObject(hdc,

GetStockObject(BLACK_PEN)));

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