Закрашивание внутренней области окна

Напомним, что кисть можно использовать еще и для закрашивания внутренней области окна . Для этого идентификатор кисти следует записать в поле hbrBackground структуры типа WNDCLASS перед регистрацией класса окна:

wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);

Установка начальных координат кисти

Начальные координаты кисти (brush origin ) - это атрибут контекста отображения. Он используются для определения координат точки внутри кисти, которая будет служить начальной при закраске внутренней области фигуры или окна. По умолчанию используются координаты (0,0), соответствующие верхнему левому углу кисти (в системе координат, выбранной в контекст отображения по умолчанию).

Если кисть используется для закраски внутренней области окна, верхний левый угол изображения кисти совмещается с верхним левым углом этой области. Затем изображение кисти многократно повторяется с шагом 8 пикселов.

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

Приложение может изменить начальные координаты кисти (сдвинуть кисть) при помощи функций SetBrushOrg и UnrealizeObject.

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

BOOL WINAPI UnrealizeObject(HGDIOBJ hbrush);

В этом случае система сбросит координаты кисти после выбора ее в контекст отображения. После сброса надо установить новые значения координат кисти, вызвав функцию SetBrushOrg :

DWORD WINAPI SetBrushOrg(HDC hdc, int nx, int ny);

Параметры nx и ny определяют новые значения для начальных координат кисти пикселах (от 0 до 7).

В завершении следует снова выбрать кисть в контекст отображения при помощи макрокоманды SelectBrush.

Приложение LINER

Для демонстрации функций рисования графических изображений в различных режимах фона и с использованием различных растровых операций мы подготовили приложение LINER. Кроме всего прочего, в этом приложении мы получаем контекст отображения, пригодный для рисования во всем окне, в частности, в области заголовка окна (рис. 2.23).

Закрашивание внутренней области окна - student2.ru

Рис. 2.23. Приложение LINER

Меню "Draw" предназначено для выбора фигур, отображаемых в окне приложения. Вы можете выбрать прямые линии (строка "Lines"), ломаную линию (строка "Polyline"), дугу эллипса ("Arc"), прямоугольники ("Rectangles"), многоугольники ("Polygon"), эллипс ("Ellipse"), окружность ("Circle"), сегмент эллипса ("Chord") или сектор эллипса ("Pie").

Запустите приложение LINER (готовый загрузочный модуль и исходные тексты приложения есть на дискете, которую можно купить вместе с книгой) и выберите из меню "Draw" строку "Rectangles". В главном окне будет нарисовано несколько прямоугольников, в том числе один прямоугольник будет нарисован по периметру внутренней области окна.

По умолчанию сразу после запуска приложения используется режим фона OPAQUE. Смените его на TRANSPARENT, выбрав соответствующую строку из меню "Background Mode". Режим фона изменится на прозрачный (рис. 2.24).

Закрашивание внутренней области окна - student2.ru

Рис. 2.24. Прозрачный режим фона

Посмотрите, как отражается изменение фона на рисовании других фигур, например, прямых линий (рис. 2.25).

Закрашивание внутренней области окна - student2.ru

Рис. 2.25. Рисование прямых линий различной толщины и стиля

Меню "ROP" позволит вам провести эксперименты с различными растровыми операциями.

Выбрав из меню "Draw" строку "Polygon", вы сможете посмотреть, как закрашиваются самопересекающиеся многоугольники в режимах ALTERNATE и WINDING (рис. 2.26).

Закрашивание внутренней области окна - student2.ru

Рис. 2.26. Режимы закрашивания многоугольников

Главный файл приложения LINER приведен в листинге 2.1.

Листинг 2.1. Файл liner/liner.cpp

// ----------------------------------------// Приложение LINER// Демонстрация использования функций// рисования графических изображений// ---------------------------------------- #define STRICT#include <windows.h>#include <windowsx.h>#include <mem.h>#pragma hdrstop #include "liner.hpp" // Прототипы функцийBOOL InitApp(HINSTANCE);LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);void DrawLines(HDC);void DrawPolyline(HDC);void DrawArc(HDC);void DrawRectangles(HDC);void DrawPolygon(HDC);void DrawEllipse(HDC);void DrawCircle(HDC);void DrawPie(HDC);void DrawChord(HDC); // Имя класса окнаchar const szClassName[] = "LinerClass"; // Заголовок окнаchar const szWindowTitle[] = "Liner"; // Размеры внутренней области окнаshort cxClient, cyClient; // Код выбранной строки меню "Draw"int nFigures = 0; // Режим фонаint nBkMode = OPAQUE; // Код растровой операцииint nROP2 = R2_COPYPEN; // =====================================// Функция WinMain// =====================================#pragma argsused int PASCALWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow){ MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложения // Инициализируем приложение if(!InitApp(hInstance)) return FALSE; // После успешной инициализации приложения создаем // главное окно приложения hwnd = CreateWindow( szClassName, // имя класса окна szWindowTitle, // заголовок окна WS_OVERLAPPEDWINDOW, // стиль окна CW_USEDEFAULT, // задаем размеры и расположение CW_USEDEFAULT, // окна, принятые по умолчанию CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, NULL); // Если создать окно не удалось, завершаем приложение if(!hwnd) return FALSE; // Рисуем главное окно ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); // Запускаем цикл обработки сообщений while(GetMessage(&msg, 0, 0, 0)) { DispatchMessage(&msg); } return msg.wParam;} // =====================================// Функция InitApp// Выполняет регистрацию класса окна// ===================================== BOOLInitApp(HINSTANCE hInstance){ ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна // Записываем во все поля структуры нулевые значения memset(&wc, 0, sizeof(wc)); // Подключаем меню wc.lpszMenuName = "APP_MENU"; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); wc.lpszClassName = (LPSTR)szClassName; // Регистрация класса aWndClass = RegisterClass(&wc); return (aWndClass != 0);} // =====================================// Функция WndProc// ===================================== LRESULT CALLBACK _exportWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){ HDC hdc; PAINTSTRUCT ps; switch (msg) { // При изменении размеров окна сохраняем // новые значения для ширины и высоты case WM_SIZE: { cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; } // Рисование в окне case WM_PAINT: { HBRUSH hbrush, hbrushOldBrush; int nCapHeight, nFrameHeight; // Рисуем в области заголовка окна // Получаем контекст отображения для // всего окна hdc = GetWindowDC(hwnd); // Определяем высоту заголовка окна nCapHeight = GetSystemMetrics(SM_CYCAPTION); // Определяем толщину рамки окна nFrameHeight = GetSystemMetrics(SM_CYFRAME); // Создаем кисть зеленого цвета hbrush = CreateSolidBrush(RGB(0,0xff,0)); // Выбираем кисть в контекст отображения, сохраняя // идентификатор старой кисти hbrushOldBrush = SelectBrush(hdc, hbrush); // Рисуем зеленый прямоугольник в левой части // заголовка окна Rectangle(hdc, 2*nCapHeight, nFrameHeight, 4*nCapHeight, nCapHeight); // Создаем и выбираем зеленую кисть hbrush = CreateSolidBrush(RGB(0xff,0,0)); SelectBrush(hdc, hbrush); // Вписываем в прямоугольник эллипс // красного цвета Ellipse(hdc, 2*nCapHeight, nFrameHeight, 4*nCapHeight, nCapHeight); // Выбираем старую кисть SelectBrush(hdc, hbrushOldBrush); // Освобождаем контекст отображения, // позволяющий рисовать во всем окне ReleaseDC(hwnd, hdc); // Рисуем во внутренней области окна // Получаем контекст отображения для // рисования во внутренней области окна hdc = BeginPaint(hwnd, &ps); // Устанавливаем метрическую систему // координат с началом координат в // левом нижнем углу внутренней области // окна SetMapMode(hdc, MM_LOMETRIC); SetViewportOrg(hdc, 0, cyClient); // Устанавливаем режим отображения и // растровую операцию SetBkMode(hdc, nBkMode); SetROP2(hdc, nROP2); // В зависимости от содержимого переменной // nFigures вызываем одну из функций рисования if(nFigures == CM_LINES) { DrawLines(hdc); // прямые линии } else if(nFigures == CM_ARC) { DrawArc(hdc); // дуга окружности } else if(nFigures == CM_RECT) { DrawRectangles(hdc); // прямоугольники } else if(nFigures == CM_POLYGON) { DrawPolygon(hdc); // многоугольники } else if(nFigures == CM_ELLIPSE) { DrawEllipse(hdc); // эллипс } else if(nFigures == CM_CIRCLE) { DrawCircle(hdc); // окружность } else if(nFigures == CM_PIE) { DrawPie(hdc); // сектор эллипса } else if(nFigures == CM_CHORD) { DrawChord(hdc); // сегмент эллипса } else if(nFigures == CM_POLYLINE) { DrawPolyline(hdc); // ломаная линия } // Освобождаем контекст отображения EndPaint(hwnd, &ps); return 0; } // Обработка сообщений от меню case WM_COMMAND: { switch (wParam) { case CM_HELPABOUT: { MessageBox(hwnd, "Liner, v.1.0\n" "Drawing Graphics Demo\n" "(C) Frolov A.V., 1994", "About Liner", MB_OK | MB_ICONINFORMATION); return 0; } // Режим непрозрачного фона case CM_OPAQUE: { // Записываем код режима nBkMode = OPAQUE; // Перерисовываем окно приложения InvalidateRect(hwnd, NULL, TRUE); return 0; } // Режим прозрачного фона case CM_TRANSPARENT: { nBkMode = TRANSPARENT; InvalidateRect(hwnd, NULL, TRUE); return 0; } // Выбор растровой операции case CM_R2_BLACK: { // Записываем код растровой операции nROP2 = R2_BLACK; // Перерисовываем окно приложения InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOTMERGEPEN: { nROP2 = R2_NOTMERGEPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MASKNOTPEN: { nROP2 = R2_MASKNOTPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOTCOPYPEN: { nROP2 = R2_NOTCOPYPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MASKPENNOT: { nROP2 = R2_MASKPENNOT; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOT: { nROP2 = R2_NOT; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_XORPEN: { nROP2 = R2_XORPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOTMASKPEN: { nROP2 = R2_NOTMASKPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MASKPEN: { nROP2 = R2_MASKPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOTXORPEN: { nROP2 = R2_NOTXORPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOP: { nROP2 = R2_NOP; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MERGENOTPEN: { nROP2 = R2_MERGENOTPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_COPYPEN: { nROP2 = R2_COPYPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MERGEPENNOT: { nROP2 = R2_MERGEPENNOT; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MERGEPEN: { nROP2 = R2_MERGEPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_WHITE: { nROP2 = R2_WHITE; InvalidateRect(hwnd, NULL, TRUE); return 0; } // Выбор из меню "Draw" case CM_LINES: { nFigures = CM_LINES; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_POLYLINE: { nFigures = CM_POLYLINE; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_ARC: { nFigures = CM_ARC; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_RECT: { nFigures = CM_RECT; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_POLYGON: { nFigures = CM_POLYGON; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_ELLIPSE: { nFigures = CM_ELLIPSE; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_CIRCLE: { nFigures = CM_CIRCLE; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_PIE: { nFigures = CM_PIE; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_CHORD: { nFigures = CM_CHORD; InvalidateRect(hwnd, NULL, TRUE); return 0; } // Завершаем работу приложения case CM_FILEEXIT: { DestroyWindow(hwnd); return 0; } default: return 0; } } case WM_DESTROY: { PostQuitMessage(0); return 0; } default: break; } return DefWindowProc(hwnd, msg, wParam, lParam);}

Исходные тексты обильно снабжены комментариями, поэтому мы сделаем только самые необходимые пояснения.

При регистрации класса окна указываются стили CS_HREDRAW и CS_VREDRAW, в результате чего окно перерисовывается при изменении его высоты или ширины:

wc.style = CS_HREDRAW | CS_VREDRAW;

Функция окна содержит обработчик сообщения WM_SIZE, который сохраняет размеры внутренней области окна в глобальных переменных cxClient и cyClient.

Обработчик сообщения WM_PAINT два раза получает контекст отображения. Вначале он получает контекст отображения, позволяющий рисовать во всем окне приложения:

hdc = GetWindowDC(hwnd);

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

После этого указанный контекст отображения освобождается:

ReleaseDC(hwnd, hdc);

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

SetMapMode(hdc, MM_LOMETRIC);SetViewportOrg(hdc, 0, cyClient);

Далее в соответствии с содержимым глобальной переменной nBkMode устанавливается режим фона:

SetBkMode(hdc, nBkMode);

Первоначально в этой переменной находится значение OPAQUE. Вы можете изменить содержимое переменной nBkMode с помощью меню "Background Mode" на TRANSPARENT.

Аналогично устанавливается растровая операция, используемая для рисования:

SetROP2(hdc, nROP2);

Далее обработчик сообщения WM_PAINT анализирует содержимое переменной nFigures, которое сразу после запуска приложения равно 0. Когда вы выбираете строку из меню "Draw", в эту переменную записывается идентификатор выбранной из меню строки. При обработке сообщения WM_PAINT в зависимости от содержимого переменной вызывается одна из нескольких функций, рисующих различные фигуры. Исходные тексты этих функций вынесены в отдельный файл (листинг 2.2).

Перед возвратом управления контекст отображения освобождается функцией EndPaint.

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

case CM_TRANSPARENT:{ nBkMode = TRANSPARENT; InvalidateRect(hwnd, NULL, TRUE); return 0;}

Функции, рисующие изображения, мы вынесли в отдельный файл (листинг 2.2).

Листинг 2.2. Файл liner/drawfn.cpp

// ----------------------------------------// Функции для приложения LINER// ----------------------------------------#define STRICT#include <windows.h>#include <windowsx.h>#include <mem.h>#include "liner.hpp" // Прототипы функцийvoid DrawLines(HDC);void DrawPolyline(HDC);void DrawArc(HDC);void DrawRectangles(HDC);void DrawPolygon(HDC);void DrawEllipse(HDC);void DrawCircle(HDC);void DrawPie(HDC);void DrawChord(HDC); // Размеры внутренней области окнаextern short cxClient, cyClient; // -------------------------------------------// DrawLines// Рисование линий различной толщины и стиля// -------------------------------------------void DrawLines(HDC hdc){ HPEN hpenW10, hpenW50; HPEN hpenDot, hpenDash, hpenDashDot, hpenOldPen; // Создаем несколько перьев: два пера толщиной // 1 мм и 5 мм, пунктирное, штриховое и // штрих-пунктирное hpenW10 = CreatePen(PS_SOLID, 10, RGB(0,0,0)); hpenW50 = CreatePen(PS_SOLID, 50, RGB(0,0,0)); hpenDot = CreatePen(PS_DOT, 0, RGB(0,0,0)); hpenDash = CreatePen(PS_DASH, 0, RGB(0,0,0)); hpenDashDot = CreatePen(PS_DASHDOT, 0, RGB(0,0,0)); // Рисуем тонкую линию пером, выбранным в контекст // отображения по умолчанию, и подписываем эту линию MoveToEx(hdc, 100, 100, NULL); LineTo(hdc, 600, 100); TextOut(hdc, 700, 100, "PS_SOLID, 1 pixel", 17); // Выбираем перо толщиной 1 мм hpenOldPen = SelectPen(hdc, hpenW10); // Рисуем линию выбранным пером MoveToEx(hdc, 100, 200, NULL); LineTo(hdc, 600, 200); TextOut(hdc, 700, 200, "PS_SOLID, 1 mm", 14); // Перебираем остальные перья SelectPen(hdc, hpenW50); MoveToEx(hdc, 100, 300, NULL); LineTo(hdc, 600, 300); TextOut(hdc, 700, 300, "PS_SOLID, 5 mm", 14); SelectPen(hdc, hpenDot); MoveToEx(hdc, 100, 400, NULL); LineTo(hdc, 600, 400); TextOut(hdc, 700, 400, "PS_DOT", 6); SelectPen(hdc, hpenDash); MoveToEx(hdc, 100, 500, NULL); LineTo(hdc, 600, 500); TextOut(hdc, 700, 500, "PS_DASH", 7); SelectPen(hdc, hpenDashDot); MoveToEx(hdc, 100, 600, NULL); LineTo(hdc, 600, 600); TextOut(hdc, 700, 600, "PS_DASHDOT", 10); // Выбираем старое перо SelectPen(hdc, hpenOldPen); // Удаляем созданные нами перья DeletePen(hpenW10); DeletePen(hpenW50); DeletePen(hpenDot); DeletePen(hpenDash); DeletePen(hpenDashDot);} // -------------------------------------------// DrawPolyline// Рисование ломаной линии// -------------------------------------------void DrawPolyline(HDC hdc){ // Массив координат точек излома POINT ptPoints[] = { {10, 10}, {100, 310}, {40, 300}, {300, 15}, {135, 340}, {113, 125}, {250, 137}, {300, 300} }; // Рисуем ломаную линию Polyline(hdc, ptPoints, sizeof ptPoints / sizeof ptPoints[0]);} // -------------------------------------------// DrawArc// Рисование дуги эллипса// -------------------------------------------void DrawArc(HDC hdc){ HPEN hpenW10, hpenOldPen; // Создаем перо толщиной 1 мм и выбираем его hpenW10 = CreatePen(PS_SOLID, 10, RGB(0,0,0)); hpenOldPen = SelectPen(hdc, hpenW10); // Рисуем дугу Arc(hdc, 100, 600, // верхний левый угол прямоугольника 800, 100, // нижний правый угол прямоугольника 650, 650, // начало 750, 0); // конец // Выбираем старое перо SelectPen(hdc, hpenOldPen); // Удаляем созданное перо DeletePen(hpenW10);} // -------------------------------------------// DrawRectangles// Рисование прямоугольников// -------------------------------------------void DrawRectangles(HDC hdc){ HPEN hpenW10, hpenOldPen; HBRUSH hbrush, hbrushOldBrush; POINT pt[2]; RECT rc = {350, 500, 500, 400}; // Рисуем прямоугольник вокруг внутренней области окна // Так как установлен метрический режим отображения, // а размеры окна, передаваемые вместе с сообщением // WM_SIZE, выражены в пикселах, выполняем // преобразование физических координат в логические pt[0].x = 0; pt[0].y = cyClient; pt[1].x = cxClient; pt[1].y = 0; DPtoLP(hdc, pt, 2); // Создаем перо толщиной 1 мм и выбираем его hpenW10 = CreatePen(PS_SOLID, 10, RGB(0,0,0)); hpenOldPen = SelectPen(hdc, hpenW10); // Рисуем прямоугольник Rectangle(hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y); // Выбираем серую кисть hbrush = GetStockBrush(GRAY_BRUSH); hbrushOldBrush = SelectBrush(hdc, hbrush); // Рисуем прямоугольник, закрашенный серым цветом Rectangle(hdc, 100, 500, 300, 50); // Создаем и выбираем кисть для штриховки hbrush = CreateHatchBrush(HS_DIAGCROSS, RGB(0,0,0)); SelectBrush(hdc, hbrush); // Рисуем заштрихованный прямоугольник Rectangle(hdc, 50, 300, 500, 100); // Выбираем старое перо и кисть SelectPen(hdc, hpenOldPen); SelectBrush(hdc, hbrushOldBrush); // Заштриховываем прямоугольную область кистью // hbrush, которая НЕ ВЫБРАНА в контекст FillRect(hdc, &rc, hbrush); // Рисуем прямоугольник со скругленными углами RoundRect(hdc, 550, 200, 800, 100, 50, 50); // Удаляем созданные нами перо и кисть DeletePen(hpenW10); DeleteBrush(hbrush);} // -------------------------------------------// DrawPolygon// Рисование многоугольника// -------------------------------------------void DrawPolygon(HDC hdc){ HBRUSH hbrush, hbrushOldBrush; int nOldPolyFillMode; // Координаты вершин первого многоугольника POINT ptPoints1[] = { {10, 10}, {100, 310}, {40, 300}, {300, 15}, {135, 340}, {113, 125}, {250, 137}, {300, 300} }; // Координаты вершин второго многоугольника POINT ptPoints2[] = { {310, 10}, {400, 310}, {340, 300}, {600, 15}, {435, 340}, {413, 125}, {550, 137}, {600, 300} }; // Выбираем встроенную серую кисть hbrush = GetStockBrush(GRAY_BRUSH); hbrushOldBrush = SelectBrush(hdc, hbrush); // Рисуем первый многоугольник в режиме // заполнения ALTERNATE, установленном // по умолчанию Polygon(hdc, ptPoints1, sizeof ptPoints1 / sizeof ptPoints1[0]); // Устанавливаем режим заполнения WINDING nOldPolyFillMode = SetPolyFillMode(hdc, WINDING); // Рисуем второй многоугольник Polygon(hdc, ptPoints2, sizeof ptPoints2 / sizeof ptPoints2[0]); // Восстанавливаем старый режим заполнения SetPolyFillMode(hdc, nOldPolyFillMode); SelectBrush(hdc, hbrushOldBrush);} // -------------------------------------------// DrawEllipse// Рисование эллипса// -------------------------------------------void DrawEllipse(HDC hdc){ POINT pt[2]; // Эллипс будет вписан во внутреннюю область // окна, поэтому определяем координаты углов // в текущей (метрической) системе координат, // выполняя преобразование pt[0].x = 0; pt[0].y = cyClient; pt[1].x = cxClient; pt[1].y = 0; DPtoLP(hdc, pt, 2); // Рисуем эллипс Ellipse(hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);} // -------------------------------------------// DrawCircle// Рисование окружности// -------------------------------------------void DrawCircle(HDC hdc){ // Рисуем эллипс, вписанный в квадрат Ellipse(hdc, 100, 600, 600, 100);} // -------------------------------------------// DrawPie// Рисование сектора круга// -------------------------------------------void DrawPie(HDC hdc){ HPEN hpenW10, hpenOldPen; // Создаем перо и выбираем его hpenW10 = CreatePen(PS_SOLID, 10, RGB(0,0,0)); hpenOldPen = SelectPen(hdc, hpenW10); // Рисуем сектор круга Pie(hdc, 100, 600, 800, 100, 650, 650, 750, 0); // Выбираем старое перо и удаляем созданное SelectPen(hdc, hpenOldPen); DeletePen(hpenW10);} // -------------------------------------------// DrawChord// Рисование сегмента круга// -------------------------------------------void DrawChord(HDC hdc){ HPEN hpenW10, hpenOldPen; hpenW10 = CreatePen(PS_SOLID, 10, RGB(0,0,0)); hpenOldPen = SelectPen(hdc, hpenW10); // Рисуем сегмент круга Chord(hdc, 100, 600, 800, 100, 650, 650, 750, 0); SelectPen(hdc, hpenOldPen); DeletePen(hpenW10);}

Символические имена констант, используемые для идентификации строк меню, описаны в файле liner.hpp (листинг 2.3).

Листинг 2.3. Файл liner/liner.hpp

#define CM_HELPABOUT 301#define CM_OPAQUE 302#define CM_TRANSPARENT 303#define CM_FILEEXIT 304#define CM_POLYGON 305#define CM_PIE 306#define CM_CHORD 307#define CM_ELLIPSE 308#define CM_RECT 309#define CM_ARC 310#define CM_LINES 311#define CM_POLYLINE 312#define CM_CIRCLE 313 #define CM_R2_BLACK 201#define CM_R2_NOTMERGEPEN 202#define CM_R2_MASKNOTPEN 203#define CM_R2_NOTCOPYPEN 204#define CM_R2_MASKPENNOT 205#define CM_R2_NOT 206#define CM_R2_XORPEN 207#define CM_R2_NOTMASKPEN 208#define CM_R2_MASKPEN 209#define CM_R2_NOTXORPEN 210#define CM_R2_NOP 211#define CM_R2_MERGENOTPEN 212#define CM_R2_COPYPEN 213#define CM_R2_MERGEPENNOT 214#define CM_R2_MERGEPEN 215#define CM_R2_WHITE 216

Меню приложения определено в файле ресурсов liner.rc (листинг 2.4).

Листинг 2.4. Файл liner/liner.rc

#include "liner.hpp" APP_MENU MENU BEGIN POPUP "&File" BEGIN MENUITEM "E&xit", CM_FILEEXIT END POPUP "&Draw" BEGIN MENUITEM "&Lines", CM_LINES MENUITEM "&Polyline", CM_POLYLINE MENUITEM "&Arc", CM_ARC MENUITEM "&Rectangles", CM_RECT MENUITEM "P&opygon", CM_POLYGON MENUITEM "&Ellipse", CM_ELLIPSE MENUITEM "C&ircle", CM_CIRCLE MENUITEM "&Chord", CM_CHORD MENUITEM "&Pie", CM_PIE END POPUP "&Background Mode" BEGIN MENUITEM "&Opaque", CM_OPAQUE MENUITEM "&Transparent", CM_TRANSPARENT END POPUP "&ROP" BEGIN MENUITEM "R2_BLACK", CM_R2_BLACK MENUITEM "R2_NOTMERGEPEN", CM_R2_NOTMERGEPEN MENUITEM "R2_MASKNOTPEN", CM_R2_MASKNOTPEN MENUITEM "R2_NOTCOPYPEN", CM_R2_NOTCOPYPEN MENUITEM "R2_MASKPENNOT", CM_R2_MASKPENNOT MENUITEM "R2_NOT", CM_R2_NOT MENUITEM "R2_XORPEN", CM_R2_XORPEN MENUITEM "R2_NOTMASKPEN", CM_R2_NOTMASKPEN MENUITEM "R2_MASKPEN", CM_R2_MASKPEN MENUITEM "R2_NOTXORPEN", CM_R2_NOTXORPEN MENUITEM "R2_NOP", CM_R2_NOP MENUITEM "R2_MERGENOTPEN", CM_R2_MERGENOTPEN MENUITEM "R2_COPYPEN", CM_R2_COPYPEN MENUITEM "R2_MERGEPENNOT", CM_R2_MERGEPENNOT MENUITEM "R2_MERGEPEN", CM_R2_MERGEPEN MENUITEM "R2_WHITE", CM_R2_WHITE END POPUP "&Help" BEGIN MENUITEM "&About...", CM_HELPABOUT ENDEND

Файл liner.def используется для определения модуля приложения LINER (листинг 2.5).

Листинг 2.5. Файл liner/liner.def

; =============================; Файл определения модуля; =============================NAME LINERDESCRIPTION 'Приложение LINER, (C) 1994, Frolov A.V.'EXETYPE windowsSTUB 'winstub.exe'STACKSIZE 8120HEAPSIZE 1024CODE preload moveable discardableDATA preload moveable multiple

Области

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

Создание области

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

Прямоугольная область

Для создания прямоугольной области предназначены функции CreateRectRgn и CreateRectRgnIndirect :

HRGN WINAPI CreateRectRgn( int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);HRGN WINAPI CreateRectRgnIndirect(const RECT FAR* lprc);

Обе эти функции создают область прямоугольной формы, размеры которой заданы координатами верхнего левого и правого нижнего углов (для функции CreateRectRgn) или при помощи структуры типа RECT (для функции CreateRectRgnIndirect). Функции возвращают идентификатор созданной области.

Заметьте, что область создается вне всякой связи с контекстом отображения. Область - это объект, принадлежащий GDI, поэтому его следует удалить после использования. Лучше всего для этого воспользоваться макрокомандой DeleteRgn , определенной в файле windowsx.h следующим образом:

#define DeleteRgn(hrgn) DeleteObject((HGDIOBJ)(HRGN)(hrgn))

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

HRGN WINAPI CreateRoundRectRgn( int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidth, int nHeight);

Первые четыре параметра аналогичны параметрам функции CreateRectRgn. Они определяют координаты углов прямоугольной области. Последние два параметра, nWidth и nHeight, предназначены, соответственно, для определения размеров воображаемого эллипса, формирующего скругленные углы.

Наши рекомендации