Управление растровым изображением. Структура Windows-приложения. Развитие стартовой заготовки, страница 6

¨  32 bpp — 4 млрд. цветов, задаваемых 4-мя последовательными байтами (red, green, blue, alfa),

Для отображения bitmap, хранимого в виде ресурса приложения (простейший случай), следует соблюдать такую последовательность действий:

1.  Загрузить его из ресурсов в память — LoadBitmap (или из файла LoadImage),

2.  Создать контекст устройства в памяти, совместимый с контекстом окна — CreateCompatibleDC,

3.  Выбрать bitmap в этот контекст — SelectObject,

4.  При каждой перерисовке копировать biitmap из контекста в памяти в другой контекст, который связан с окном.

Копирование контекстов—это и есть самый быстрый процесс отображения bitmap (или рисования готовых объектов). При этом обычно пользуются одной из API-функций: BitBlt (простое копирование), или StretchBlt (копирование с изменением размеров).

Добавьте в состав оконной процедуры такие переменные:

static HDC hMemDC;    // Контекст устройства в памяти

static HBITMAP hImg;  // Описатель bitmap

static RECT rBmp;     // Текущий прямоугольник bitmap-изображения

static SIZE szSrc;    // Настоящие размеры bitmap

static bool bDrag;    // Флаг перемещения

static HBRUSH hbrBkgnd; // Описатель кисти для закраски фона

RECT rTmp;            // Временный прямоугольник

Вы помните, что переменные типа static не уничтожаются при выходе из оконной процедуры? Введите ветвь обработки сообщения WM_CREATE (первоначальное создание окна):

case WM_CREATE:

{

  hImg = LoadBitmap(GetModuleHandle(0), MAKEINTRESOURCE(IDB_BITMAP));// Загружаем bitmap из ресурсов

  BITMAP bm;       // Определяем его размеры с помощью структуры BITMAP

  GetObject (hImg, sizeof(BITMAP),&bm);

  szSrc.cx = bm.bmWidth;

  szSrc.cy = bm.bmHeight;

  hdc = GetDC(hWnd); // Добываем контекст устройства, связанный с окном

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

  SelectObject(hMemDC, hImg); // Выбираем bitmap в этот контекст

  ReleaseDC (hWnd, hdc);      // Освобождаем лимитированный ресурс системы

  hbrBkgnd = CreateSolidBrush (RGB(255,255,220));// Кисть цвета фона (для стирания bitmap при его перемещении)

  SetRect (&rBmp, 1, 1, szSrc.cx-2, szSrc.cy-2); // Размеры прямоугольника с учетом толщины рамки

  break;

}

Введите ветвь обработки сообщения WM_ERASEBKGND (закрашивание фона окна):

case WM_ERASEBKGND:

{

  hdc = (HDC)wParam; // Добываем контекст устройства, который прислала система

  HBRUSH hOld = (HBRUSH)SelectObject (hdc, hbrBkgnd); // Выбираем нашу кисть, запоминая текущую

  RECT r;

  GetClientRect(hWnd, &r); // Определяем размеры клиентской области окна

  PatBlt(hdc, r.left, r.top, r.right - r.left, r.bottom - r.top, PATCOPY); // Закрашиваем

  SelectObject(hdc, hOld); // Возвращаем перо в контекст устройства

  return TRUE;

}

Реакция окна на сообщение о перерисовке вызывает функцию StretchBlt, которая копирует изображение из одного контекста устройства (в памяти) в другой (связанный с окном). Эта функция, в отличие от BitBlt, способна растянуть или сжать изображение, подстраивая его под заданный размер.

case WM_PAINT:

  hdc = BeginPaint(hWnd, &ps);

  if (!IsRectEmpty (&rBmp))// Копируем изображение из контекста в памяти в контекст окна, одновременно изменяя размеры

     StretchBlt (hdc,rBmp.left,rBmp.top,rBmp.right-rBmp.left,rBmp.bottom-rBmp.top, // Куда

      hMemDC, 0, 0, szSrc.cx, szSrc.cy, // Откуда

      SRCCOPY);                         // Как

  SetRectEmpty (&rTarget);    // Обнуляем прямоугольник - мишень

  EndPaint (hWnd, &ps);

  break;

Для управления изображением с помощью мыши выберем такой алгоритм:

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

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

case WM_LBUTTONDOWN:

  ClipCursor(&rClient);

  ptOld.x = LOWORD(lParam);

  ptOld.y = HIWORD(lParam);

  if (PtInRect(&rBmp, ptOld))