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

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

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

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

4.2. Приложение BMPLOGO

Приведем пример приложения BMPLOGO, которое демонстрирует работу с битовыми изображениями в формате DDB. Это приложение создает одно битовое изображение в памяти и рисует его в верхнем левом углу окна, а также (что на наш взгляд, самое интересное), рисует текстовую строку с оттенением (рис. 4.3).

Рис. 4.3. Приложение BMPLOGO

Заметим, что для рисования слова "Bitmap" мы не пользовались какими-либо особенностями шрифтов True Type. Эффект теней был получен при помощи двухкратного вывода монохромного битового изображения со сдвигом, причем каждый раз мы использовали различные растровые операции.

Исходный текст главного модуля приложения представлен в листинге 4.1.


Листинг 4.1. Файл bmplogo/bmplogo.cpp


// ----------------------------------------
// Приложение BMPLOGO
// Демонстрация различных способов рисования
// битовых изображений DDB
// ----------------------------------------

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

// Прототипы функций
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawBitmapRop(HDC hDC, int x, int y, HBITMAP hBitmap, DWORD dwRop);

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

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

// Размеры внутренней области окна
short cxClient, cyClient;

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

// Битовое изображение
BYTE bBytes[] =
{
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
  0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
  0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
  0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
  0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
  0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
  0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

// Структура, описывающая битовое изображение
BITMAP bmp =
{
  0, 64, 9, 8, 1, 1, NULL
};

// =====================================
// Функция 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.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);

  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.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_CREATE:
    {
      return 0;
    }

    // При изменении размеров окна сохраняем
    // новые значения для ширины и высоты
    case WM_SIZE:
    {
      cxClient = LOWORD(lParam);
      cyClient = HIWORD(lParam);
      return 0;
    }

    // Рисование в окне
    case WM_PAINT:
    {
      HBITMAP bmLogo1, bmLogo2;

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

      // Загружаем изображение из ресурсов приложения
      bmLogo1 = LoadBitmap(hInst, "Logo1");

      // Выводим изображение два раза со смещением,
      // используя разные коды растровых операций.
      // Это дает эффект тени
      DrawBitmapRop(hdc, 20, 20, bmLogo1, SRCAND);
      DrawBitmapRop(hdc, 15, 15, bmLogo1, MERGEPAINT);

      // Завершаем формирование структуры bmp
      bmp.bmBits = (LPSTR)bBytes;

      // Создаем битовое изображение из массива
      // данных, расположенных в памяти
      bmLogo2 = CreateBitmapIndirect(&bmp);

      // Рисуем это изображение
      DrawBitmapRop(hdc, 0, 0, bmLogo2, SRCCOPY);

      // Удаляем изображения 
      DeleteBitmap(bmLogo1);
      DeleteBitmap(bmLogo2);

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

    case WM_DESTROY:
    {
      PostQuitMessage(0);
      return 0;
    }

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

Здесь для нас представляет интерес главным образом обработчик сообщения WM_PAINT, который и рисует битовые изображения.

Изображение слова "Bitmap" находится в ресурсах и имеет идентификатор Logo1. Для загрузки его в памяти вызывается функция LoadBitmap:

bmLogo1 = LoadBitmap(hInst, "Logo1");

Далее изображение выводится в первый раз, при этом используется растровая операция SRCAND:

DrawBitmapRop(hdc, 20, 20, bmLogo1, SRCAND);

Затем то же самое изображение выводится еще раз, но с небольшим смещением и с использованием другой растровой операции:

DrawBitmapRop(hdc, 15, 15, bmLogo1, MERGEPAINT);

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

Затем обработчик сообщения WM_PAINT создает в памяти и выводит на экран еще одно монохромное битовое изображение:

bmp.bmBits = (LPSTR)bBytes;
bmLogo2 = CreateBitmapIndirect(&bmp);
DrawBitmapRop(hdc, 0, 0, bmLogo2, SRCCOPY);

При создании изображения используются приемы, описанные в предыдущем разделе.

Перед возвратом управления обработчик удаляет оба созданных им битовых изображения:

DeleteBitmap(bmLogo1);
DeleteBitmap(bmLogo2);

Листинг 4.2. Файл bmplogo/drawbmp.cpp


// ----------------------------------------
// Рисование изображения типа bitmap
// с использованием различных растровых операций
// ----------------------------------------

#define STRICT
#include <windows.h>

void DrawBitmapRop(HDC hDC, int x, int y, 
    HBITMAP hBitmap, DWORD dwRop)
{
  HBITMAP hbm, hOldbm;
  HDC hMemDC;
  BITMAP bm;
  POINT  ptSize, ptOrg;

  // Создаем контекст памяти, совместимый
  // с контекстом отображения
  hMemDC = CreateCompatibleDC(hDC);

  // Выбираем изображение bitmap в контекст памяти
  hOldbm = (HBITMAP)SelectObject(hMemDC, hBitmap);

  // Если не было ошибок, продолжаем работу
  if (hOldbm)
  {
    // Для контекста памяти устанавливаем тот же
    // режим отображения, что используется в
    // контексте отображения
    SetMapMode(hMemDC, GetMapMode(hDC));

    // Определяем размеры изображения
    GetObject(hBitmap, sizeof(BITMAP), (LPSTR) &bm);

    ptSize.x = bm.bmWidth;   // ширина
    ptSize.y = bm.bmHeight;  // высота

    // Преобразуем координаты устройства в логические
    // для устройства вывода
    DPtoLP(hDC, &ptSize, 1);

    ptOrg.x = 0;
    ptOrg.y = 0;

    // Преобразуем координаты устройства в логические
    // для контекста памяти
    DPtoLP(hMemDC, &ptOrg, 1);

    // Рисуем изображение bitmap
    BitBlt(hDC, x, y, ptSize.x, ptSize.y,
           hMemDC, ptOrg.x, ptOrg.y, dwRop);

    // Восстанавливаем контекст памяти
    SelectObject(hMemDC, hOldbm);
  }

  // Удаляем контекст памяти
  DeleteDC(hMemDC);
}

Файл описания ресурсов приложения (листинг 4.3) содержит только одну строку, которая ссылается на файл битового изображения logo1.bmp.


Листинг 4.3. Файл bmplogo/bmplogo.rc


Logo1 BITMAP logo1.bmp

В листинге 4.4 показано битовое изображение, содержащее слово "Bitmap".


Листинг 4.4. Файл bmplogo/logo1.bmp



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


Листинг 4.5. Файл bmplogo/bmplogo.def


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

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