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

¨  Bitmap, копируемый в контекст, связанный с окном, следит за размерами клиентской области и периодически (в обработке WM_SIZE) подстраивает свои размеры под них. Само изображение при этом имеет меньший размер и является частью клиентского контекста. Изображение перемещается мышью в пределах большого bitmap'а. В этом сценарии важно, что перемещение изображения происходит в контексте, который не отображается в окне (он в памяти), а не в контексте hdc (на глазах у пользователя).

¨  Bitmap, копируемый в контекст, связанный с окном, по бокам имеет поля цвета окна, которые используются как бульдозер, заглаживающий поверхность для рисования. При перемещении они стирают остатки старого изображения. В этом сценарии важно первоначально (один раз) закрасить фон и не слишком быстро перемещать изображение, чтобы размеров полей хватило на закраску огрехов.

Рассмотрим реализацию первого способа, так как он дает фундаментальное решение. В этом случае нам придется завести еще один (уже третий) контекст устройства hdcClient, который будет соответствовать всей клиентской области окна. Существующий контекст hMemDC уже занят исходным (неискаженным) изображением и его, видимо, не удастся модифицировать без потери производительности. Алгоритм использования трех контекстов в процессе перерисовки представляется таким:

¨  В контекст hdcClient выбираем новый bitmap, размеры которого соответствуют размерам клиентской области окна, и закрашиваем его цветом фона (PatBlt).

¨  Копируем в этот контекст (hdcClient) изображение, которое заготовлено в контексте hMemDC. Позиция изображения (в пределах hdcClient) и его размеры определяются прямоугольником rBmp, который редактируется пользователем, как и ранее. При копировании используем функцию StretchBlt.

¨  Копируем весь контекст hdcClient (то есть, всю клиентскую область окна) в контекст hdc, который связан с окном. Здесь достаточно использовать функцию BitBlt.

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

Оставим возможность изменять размер и позицию изображения, перенося его в соприкасающийся или не соприкасающейся прямоугольник, указанный пользователем. Во избежание ошибок ввода приведем полный текст оконной процедуры WndProc.

LRESULT WINAPI WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

HDC hdc;              // Контекст устройства, связанный с окном

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

PAINTSTRUCT ps;         // Данные для рисования

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

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

static POINT ptOld;   // Координаты курсора

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

static RECT rTarget;  // Прямоугольник – мишень копирования

static RECT rClient;  // Прямоугольник клиентской области окна

static SIZE szSrc;    // Исходные размеры bitmap

static SIZE szClient; // Размеры клиентской области

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

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

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

switch(msg)

{

case WM_CREATE:

  {

   hImg = LoadBitmap(GetModuleHandle(0), MAKEINTRESOURCE(IDB_BITMAP));

   BITMAP bm;

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

   szSrc.cx = bm.bmWidth;

   szSrc.cy = bm.bmHeight;

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

   hMemDC = CreateCompatibleDC(hdc);  // Контекст в памяти (изображение)

   hdcClient = CreateCompatibleDC(hdc); // Контекст в памяти (клиентская область)

   SelectObject (hMemDC, hImg);

   ReleaseDC (hWnd, hdc);

   hbrBkgnd = CreateSolidBrush (RGB(255,255,220));

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

   break;

  }

case WM_ERASEBKGND: return TRUE;

case WM_PAINT:

{

  hdc = BeginPaint(hWnd, &ps);

  HBITMAP hBmp = CreateCompatibleBitmap (hdc, szClient.cx, szClient.cy);

  SelectObject (hdcClient, hBmp);

  HBRUSH hOld = (HBRUSH)SelectObject (hdcClient, hbrBkgnd);

  PatBlt (hdcClient, 0, 0, szClient.cx, szClient.cy, PATCOPY);

  if (!IsRectEmpty (&rBmp))

  {

   StretchBlt (hdcClient, rBmp.left,rBmp.top,rBmp.right-rBmp.left,rBmp.bottom-rBmp.top,