Графический интерфейс GDI в Microsoft Windows

         

Приложение REGIONS


Для демонстрации использования комбинированных областей мы подготовили приложение REGIONS. Это приложение создает три области: прямоугольную и две эллиптические разного размера. Прямоугольная область объединяется с первой эллиптической областью. Из полученного результата вырезается вторая эллиптическая область (меньших размеров).

Полученная комбинированная область используется в качестве маски, через которую в окно приложения выводится текст (рис. 2.27). Для большей наглядности границы области ограничения обведены зеленой кистью при помощи функции FrameRgn.

Рис. 2.27. Вывод текста с использованием области ограничения

Исходный текст приложения приведен в листинге 2.6.

Листинг 2.6. Файл regions/regions.cpp

// ---------------------------------------- // Приложение REGIONS // Демонстрация использования области ограничения // ----------------------------------------

#define STRICT #include <windows.h> #include <windowsx.h> #include <mem.h>

// Прототипы функций BOOL InitApp(HINSTANCE); LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);

// Имя класса окна char const szClassName[] = "RegionsClass";

// Заголовок окна char const szWindowTitle[] = "Regions";

// Размеры внутренней области окна short cxClient, cyClient;

// Размеры символов int cxChar, cyChar;

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

// ===================================== // Функция WinMain // ===================================== #pragma argsused

int PASCAL WinMain(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 // Выполняет регистрацию класса окна // =====================================

BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна // Записываем во все поля структуры нулевые значения memset(&wc, 0, sizeof(wc));

wc.lpszMenuName = NULL; 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(WHITE_BRUSH); wc.lpszClassName = (LPSTR)szClassName;

// Регистрация класса aWndClass = RegisterClass(&wc);

return (aWndClass != 0); }

// ===================================== // Функция WndProc // =====================================

LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static TEXTMETRIC tm; static HRGN hrgn1, hrgn2, hrgn3, hrgnTemp, hrgnClip; HBRUSH hbrush;

switch (msg) { case WM_CREATE: { // Определяем метрику шрифта hdc = GetDC(hwnd); GetTextMetrics(hdc, &tm); ReleaseDC(hwnd, hdc);

// Высота и средняя ширина букв cyChar = tm.tmHeight + tm.tmExternalLeading; cxChar = tm.tmAveCharWidth;



// Область ограничения не задана hrgnClip = NULL;

return 0; }

// При изменении размеров окна сохраняем // новые значения для ширины и высоты, // а также определяем область ограничения case WM_SIZE: { cxClient = LOWORD(lParam); cyClient = HIWORD(lParam);

// Если область ограничения была определена раньше, // удаляем ее if(hrgnClip) DeleteRgn(hrgnClip);

// Формируем область ограничения hrgnClip = CreateEllipticRgn(0, 0, cxClient, cyClient);

// Временная область ограничения hrgnTemp = CreateEllipticRgn(0, 0, cxClient, cyClient);

// Первая эллиптическая область hrgn1 = CreateEllipticRgn(0, 0, cxClient, cyClient);

// Вторая эллиптическая область hrgn2 = CreateEllipticRgn(cxClient/3, cyClient/3, 2*(cxClient/3), 2*(cyClient/3));

// Прямоугольная область hrgn3 = CreateRectRgn(cxClient/20, cyClient/20, 19*(cxClient/20), 19*(cyClient/20));

// Комбинируем области UnionRgn(hrgnTemp, hrgn1, hrgn3); SubtractRgn(hrgnClip, hrgnTemp, hrgn2);

// Удаляем временные области DeleteRgn(hrgn1); DeleteRgn(hrgn2); DeleteRgn(hrgn3); DeleteRgn(hrgnTemp); return 0; }

// Рисование в окне case WM_PAINT: { RECT rc;

// Получаем контекст отображения для // рисования во внутренней области окна hdc = BeginPaint(hwnd, &ps);

// Выбираем встроенную кисть зеленого цвета hbrush = CreateSolidBrush(RGB(0, 0xff, 0));

// Обводим границы области FrameRgn(hdc, hrgnClip, hbrush, 2, 5);

// Выбираем область ограничения в контекст // отображения SelectClipRgn(hdc, hrgnClip);

// Определяем координаты прямоугольной // области для вывода текста rc.left = cxChar; rc.top = 0; rc.right = cxClient - cxChar; rc.bottom = cyClient;

// Вывод текста DrawText(hdc, szText, lstrlen(szText), &rc, DT_LEFT | DT_WORDBREAK);

// Освобождаем контекст отображения EndPaint(hwnd, &ps); return 0; }

case WM_DESTROY: { // удаляем область ограничения DeleteRgn(hrgnClip);

PostQuitMessage(0); return 0; }

default: break; } return DefWindowProc(hwnd, msg, wParam, lParam); }

Во время создания окна обработчик сообщения WM_CREATE определяет метрику шрифта и записывает значение NULL в переменную hrgnClip.


Эта переменная будет использоваться для хранения идентификатора области ограничения.

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

Затем он проверяет содержимое переменной hrgnClip. Если была задана область ограничения, она удаляется, так как при изменении размеров окна нужно сформировать новую область ограничения.

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

Далее все области, кроме hrgnClip, удаляются, так как они больше не нужны.

Приложение REGIONS рисует в окне во время обработки сообщения WM_PAINT.

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

hbrush = CreateSolidBrush(RGB(0, 0xff, 0)); FrameRgn(hdc, hrgnClip, hbrush, 2, 5);

Далее область hrgnClip выбирается в контекст отображения для использования в качестве маски при выводе текста:

SelectClipRgn(hdc, hrgnClip);

Вывод текста выполняется при помощи функции DrawText.

Перед завершением своей работы (при обработке сообщения WM_DESTROY) приложение удаляет область hrgnClip, вызывая макрокоманду DeleteRgn:

DeleteRgn(hrgnClip);

Файл определения модуля для приложения REGIONS приведен в листинге 2.7.

Листинг 2.7. Файл regions/regions.def

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


Содержание раздела