Графический интерфейс GDI в Microsoft Windows© Александр Фролов, Григорий ФроловТом 4, М.: Диалог-МИФИ, 1993, 288 стр. 2.6. Приложение 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 |