Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

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

[Назад] [Содеожание] [Дальше]