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

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

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

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

2.8. Приложение DASHLINE

Приложение DASHLINE демонстрирует использование функции LineDDA для рисования пунктирных линий увеличенной толщины (рис. 2.28). Напомним, что вы не можете создать перо для рисования таких линий обычными средствами.

Рис. 2.28. Пунктирные линии увеличенной толщины

Основной файл исходного текста приложения приведен в листинге 2.8.


Листинг 2.8. Файл dashline/dashline.cpp


// ----------------------------------------
// Приложение DASHLINE
// Демонстрация использования функции LineDDA
// ----------------------------------------

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

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

void CALLBACK _export 
  LineProc(int xPos, int yPos, LPSTR lphdc);

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

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

// Идентификатор копии приложения
HINSTANCE hInst;

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

int PASCAL
WinMain(HINSTANCE hInstance, 
        HINSTANCE hPrevInstance,
        LPSTR     lpszCmdLine, 
        int       nCmdShow)
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложения

  // Инициализируем приложение
  if(!InitApp(hInstance))
      return FALSE;

  // Сохраняем идентификатор копии приложения
  hInst = hInstance;

  // Создаем главное окно приложения
  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 FARPROC lpfnLineProc;
  HPEN hpen, hpenOldPen;

  switch (msg)
  {
    case WM_CREATE:
    {
      // Создаем переходник для функции LineProc 
      lpfnLineProc = 
         MakeProcInstance((FARPROC)LineProc, hInst);
      return 0;
    }

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

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

      // Создаем перо толщиной 3 пиксела и выбираем
      // его в контекст отображения 
      hpen = CreatePen(PS_SOLID, 3, RGB(0, 0, 0));
      hpenOldPen = SelectPen(hdc, hpen);

      // Рисуем несколько штриховых линий,
      // используя выбранное перо

      LineDDA(50, 50, 300, 50,
        (LINEDDAPROC)lpfnLineProc, (DWORD)(LPSTR)&hdc);

      LineDDA(50, 50, 300, 100,
        (LINEDDAPROC)lpfnLineProc, (DWORD)(LPSTR)&hdc);

      LineDDA(50, 50, 50, 100,
        (LINEDDAPROC)lpfnLineProc, (DWORD)(LPSTR)&hdc);

      LineDDA(50, 100, 300, 100,
        (LINEDDAPROC)lpfnLineProc, (DWORD)(LPSTR)&hdc);

      LineDDA(300, 50, 300, 100,
        (LINEDDAPROC)lpfnLineProc, (DWORD)(LPSTR)&hdc);

      // Выбираем старое перо и удаляем созданное
      SelectPen(hdc, hpenOldPen);
      DeletePen(hpen);

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

    case WM_DESTROY:
    {
      // Освобождаем переходник функции LineProc
      FreeProcInstance(lpfnLineProc);

      PostQuitMessage(0);
      return 0;
    }

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

// --------------------------------------------------
// Функция LineProc вызывается для каждой точки линии
// --------------------------------------------------
void CALLBACK _export
LineProc(int xPos, int yPos, LPSTR lphdc)
{
    // Счетчик точек
    static short cSpaces = 1;

    // Для каждой первой точки устанавливаем текущую
    // позицию пера
    if(cSpaces == 1)
    {
      MoveToEx(*(HDC FAR*) lphdc, xPos, yPos, NULL);
      cSpaces++;
    }

    // Для каждой десятой точки рисуем линию
    else if(cSpaces == 10)
    {
      LineTo(*(HDC FAR*) lphdc, xPos, yPos);
      cSpaces++;
    }

    // Для каждой двадцатой точки устанавливаем
    // текущую позицию пера и сбрасываем счетчик
    else if(cSpaces == 20)
    {
      MoveToEx(*(HDC FAR*) lphdc, xPos, yPos, NULL);
      cSpaces = 1;
    }
    else
        cSpaces++;
}

В процессе инициализации главного окна приложения при обработке сообщения WM_CREATE создается переходник для функции рисования, которая является функцией обратного вызова:

lpfnLineProc = 
   MakeProcInstance ((FARPROC)LineProc, hInst);

Рисование линий выполняется обработчиком сообщения WM_PAINT.

Этот обработчик получает контекст отображения и создает перо толщиной 3 пиксела, с помощью которого он будет рисовать пунктирную линию. Перо выбирается в контекст отображения:

hpen = CreatePen(PS_SOLID, 3, RGB(0, 0, 0));
hpenOldPen = SelectPen(hdc, hpen);

Далее приложение рисует несколько пунктирных линий, вызывая функцию LineDDA:

LineDDA(50, 50, 300, 50,
  (LINEDDAPROC)lpfnLineProc, (DWORD)(LPSTR)&hdc);

Идентификатор контекста отображения, необходимый для рисования линии, передается через последний параметр функции.

В функции рисования есть статический счетчик cSpaces, с помощью которого организуется цикл рисования штриховых линий. Первоначальное значение этого счетчика равно 1.

Алгоритм рисования понятен из комментариев, которые есть в исходном тексте функции. Заметим, что для рисования линии вы можете использовать любые функции. Можно, например, нарисовать линию, состоящую из окружностей, эллипсов, прямоугольников или даже из битовых изображений.

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


Листинг 2.9. Файл dashline/dashline.def


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

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