95 в двух томах Том I



Pdf просмотр
страница13/41
Дата27.11.2016
Размер4.32 Mb.
Просмотров7789
Скачиваний0
ТипРеферат
1   ...   9   10   11   12   13   14   15   16   ...   41
RANDRECT.MAK
#------------------------
# RANDRECT.MAK make file
#------------------------ randrect.exe : randrect.obj
$(LINKER) $(GUIFLAGS) -OUT:randrect.exe randrect.obj $(GUILIBS) randrect.obj : randrect.c
$(CC) $(CFLAGS) randrect.c
RANDRECT.C
/*------------------------------------------
RANDRECT.C -- Displays Random Rectangles
(c) Charles Petzold, 1996
------------------------------------------*/
#include
#include
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void DrawRectangle(HWND); int cxClient, cyClient; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{ static char szAppName[] = "RandRect";
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, "Random Rectangles",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while(TRUE)

116
{ if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{ if(msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
} else
DrawRectangle(hwnd);
} return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{ switch(iMsg)
{ case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_DESTROY:
PostQuitMessage(0); return 0;
} return DefWindowProc(hwnd, iMsg, wParam, lParam);
} void DrawRectangle(HWND hwnd)
{
HBRUSH hBrush;
HDC hdc;
RECT rect; if(cxClient == 0 || cyClient == 0) return;
SetRect(&rect, rand() % cxClient, rand() % cyClient, rand() % cxClient, rand() % cyClient); hBrush = CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256)); hdc = GetDC(hwnd);
FillRect(hdc, &rect, hBrush);
ReleaseDC(hwnd, hdc);
DeleteObject(hBrush);
}
Рис. 4.21 Программа RANDRECT
Программа применяет функции SetRect и FillRect, которые были описаны выше, с координатами прямоугольника и цветом сплошной кисти, вычисленными на основе случайных величин, полученных от функции rand языка C.
В главе 14 будет приведена другая версия этой программы, основанная на принципе многопоточности.

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
#include
#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));
}

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
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)));

125
MoveToEx(hdc, 10 + 30 * i, 25, NULL);
LineTo (hdc, 20 + 30 * i, 75);
LineTo (hdc, 30 + 30 * i, 25);
}
EndPaint(hwnd, &ps); return 0; case WM_DESTROY:
PostQuitMessage(0); return 0;
} return DefWindowProc(hwnd, iMsg, wParam, lParam);
}



Поделитесь с Вашими друзьями:
1   ...   9   10   11   12   13   14   15   16   ...   41


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал