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

¨  Если перо красное (8 младших бит цвета установлены в 1), а фон белый (то есть присутствуют все 3 компонента цвета — 3 байта установлены в 1), то результатом операции XOR будет цвет Cyan, так как красный компонент исчезнет (1+1=0), а оставшиеся компоненты (зеленый и синий), дают цвет Cyan;

00000000 00000000 00000000 11111111 // Перо - красное

00000000 11111111 11111111 11111111 // Фон - белый

00000000 11111111 11111111 00000000 // Результат операции XOR - Cyan

Если повторно пройтись красной линией по тому же месту (по линии цвета Cyan), то при сложении цветов единицы попадут на нули и цвет станет белым, так как все 24 бита (3 байта) цвета установятся в 1.

00000000 00000000 00000000 11111111 // Перо - красное

00000000 11111111 11111111 00000000 // Фон - Cyan

00000000 11111111 11111111 11111111 // Результат операции XOR - белый цвет

Итак, повторный проход стирает линию. В качестве упражнения повторите выкладки, при условии, что перо белое, а затем—черное. Такие упражнения шлифуют главные качества программиста—терпение и настойчивость. Черное перо являет вырожденный случай (эффект сохраняется, но контур линии отсутствует).

Тем не менее, для создания эффекта rubber-band обычно берут черное перо, но при этом задают стиль линии PS_DOT (пунктир) или PS_DASH (штрих), что в принципе равносильно черно-белому перу. Белые участки работают, как описано, а черные своей инертностью не мешают стирать и вновь воспроизводить контур линии.

Эффект переливания пунктира (натягивания и сжимания резинки) объясняется тем, что при изменении общей длины контура черные и белые участки меняют свое местоположение, узор линии начинается работать с разных стартовых позиций. Это и составляет суть эффекта rubber-band. Есть еще одно значение (R2_NOT) параметра функции SetROP2, которое успешно работает, но без эффекта резинки. Для реализации эффекта резинового прямоугольника введите в состав оконной процедуры такие переменные:

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

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

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

static RECT rTarget;   // Прямоугольник (позже он будет мишенью для копирования bitmap)

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

static HPEN hpenDot;   // Описатель пунктирного пера

Удалите все вхождения переменной ptCenter. Вместо нее мы будем пользоваться прямоугольником rClient. Затем добавьте обработку события создания окна (WM_CREATE) и трех мышиных событий.

case WM_CREATE: // Реакция на создание окна

{

hpenDot = CreatePen (PS_DOT, 1, RGB(0, 0, 0));// Пунктирное перо для рисования динамического прямоугольника

break;

}

case WM_LBUTTONDOWN:   // Реакция на нажатие левой кнопки

ClipCursor(&rClient); // Ограничиваем возможности перемещения курсора только клиентской областью окна

ptOld.x = LOWORD (lParam); // Запоминаем текущие координаты курсора

ptOld.y = HIWORD (lParam);

break;

case WM_MOUSEMOVE:     // Реакция на движение курсора

{

if (!(wParam & MK_LBUTTON))   // Если не нажата левая кнопка мыши, уходим

return 0;

short x = LOWORD(lParam),  y = HIWORD(lParam); // Текущие координаты курсора

hdc = GetDC(hWnd);

HPEN pOld = (HPEN)SelectObject (hdc, hpenDot); // Выбираем пунктирное перо в контекст устройства

HBRUSH bOld = (HBRUSH)SelectObject (hdc, GetStockObject(NULL_BRUSH));// Выбираем прозрачную кисть

SetROP2 (hdc, R2_XORPEN); // Инверсный режим смешивания цвета. Повторное рисование линии стирает старую линию

if (!IsRectEmpty (&rTarget)) // Сначала стираем старый прямоугольник мишени

Rectangle (hdc, rTarget.left, rTarget.top, rTarget.right, rTarget.bottom);

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;