Управление растровым изображением. Альтернативные способы перерисовки динамического прямоугольника. Работа с растровыми изображениями, страница 10

Рассмотрим реализацию первого способа, так как он дает фундаментальное решение. В этом случае нам придется завести еще один (уже третий) контекст устройства 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,

hMemDC, 0, 0, szSrc.cx, szSrc.cy, SRCCOPY);

BitBlt (hdc, 0,0, szClient.cx, szClient.cy, hdcClient, 0, 0, SRCCOPY);

}

if (!IsRectEmpty (&rTarget))

DrawFocusRect (hdc, &rTarget);

SelectObject (hdcClient, hOld);

EndPaint(hWnd, &ps);

DeleteObject (hBmp);

break;

}

case WM_LBUTTONDOWN:

ClipCursor(&rClient);

ptOld.x = LOWORD (lParam);

ptOld.y = HIWORD (lParam);

if (PtInRect (&rBmp, ptOld))

bDrag = true;

break;

case WM_MOUSEMOVE:

{