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

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, nSrcWidth-2, nSrcHeight-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, nSrcWidth, nSrcHeight,  // Откуда

SRCCOPY);                                    // Как

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

EndPaint (hWnd, &ps);

break;

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

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

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

case WM_LBUTTONDOWN:

ClipCursor(&rClient);

ptOld.x = LOWORD(lParam);

ptOld.y = HIWORD(lParam);

if (PtInRect(&rBmp, ptOld))

bDrag = true;

break;

case WM_MOUSEMOVE:

{

if (!(wParam & MK_LBUTTON))

return 0;

short  x = LOWORD(lParam),  y = HIWORD(lParam);

hdc = GetDC(hWnd);

if (bDrag)    // Изображаем прямоугольник перетаскиваемого объекта

{

DrawFocusRect (hdc, &rBmp);

OffsetRect (&rBmp, x - ptOld.x, y - ptOld.y);

DrawFocusRect (hdc, &rBmp);

ptOld.x = x;      ptOld.y = y;

}

else // Изображаем пустой прямоугольник - мишень для копирования изображения

{

if (!IsRectEmpty (&rTarget))

DrawFocusRect (hdc, &rTarget);

SetRect (&rTarget, ptOld.x, ptOld.y, x, y);

if (ptOld.x > x)

{

rTarget.left = x;

rTarget.right = ptOld.x;

}

if (ptOld.y > y)

{

rTarget.top = y;

rTarget.bottom = ptOld.y;

}

DrawFocusRect (hdc, &rTarget);

}

ReleaseDC (hWnd, hdc);

break;

}

case WM_LBUTTONUP:

ClipCursor (0);

if (IntersectRect (&rTmp, &rBmp, &rTarget))

{

CopyRect (&rBmp, &rTarget);

InvalidateRect (hWnd, 0, TRUE);