Графический интерфейс 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 |

