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

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

© Александр Фролов, Григорий Фролов
Том 4, М.: Диалог-МИФИ, 1993, 288 стр.

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

2.4. Приложение LINER

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

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

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

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

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

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

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

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

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

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

Рис. 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 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  = "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 _export
WndProc(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
    END
END

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


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


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

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