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

}

if (bDrag)

{

bDrag = false;  

InvalidateRect (hWnd, 0, TRUE);

}

break;

При закрытии окна следует освобождать динамические ресурсы Windows:

case WM_DESTROY:

DeleteObject (hbrBkgnd);

DeleteDC (hMemDC);

DeleteObject (hImg);

PostQuitMessage(0);

break;

Реакцию на WM_MOVE и WM_SIZE оставьте без изменений. Для того, чтобы все заработало, надо ввести в состав проекта ресурс какого-либо изображения.

1.  Дайте команду Add4Resource4Bitmap4New4OK. Появится пустой bitmap,

2.  Замените его идентификатор на IDB_BITMAP,

3.  Дайте команду File4Open4Files of Type (Image Files),

4.  Найдите где-либо на диске и откройте в рамках студии понравившееся изображене,

5.  Скопируйте его (Ctrl+C), переключите окно (Ctrl+F6) и восстановите в окне IDB_BITMAP (Ctrl+V).

Запустите приложение (Ctrl+F5) и устраните возможные ошибки. Проанализируйте работу функции StretchBlt, изменяя размеры прямоугольника-мишени и перемещая в него существующее изображение. Попробуйте утащить изображение за пределы окна. Проверьте корректность отработки сообщений WM_SIZE и WM_MOVE.

Инверсия изображений

¨  Создайте копию файла Step03.cpp, переименуйте ее в Step04.cpp, подключите ее к проекту, а старый файл отсоедините. В ветвь обработки WM_MOUSEMOVE вновь вставьте установку растровой операции:

SetROP2 (hdc, R2_NOT);

¨  Замените все вхождения:

DrawFocusRect (hdc, &rBmp);

на:

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

а все вхождения:

DrawFocusRect (hdc, &rTarget);

на:

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

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

Объясните происходящее путем анализа булевских операций с компонетами цвета. Испытайте другие типы растровых операций, пользуйтесь документацией MSDN. Объясняйте, что происходит. Реализуйте какой-либо свой алгоритм управления изображением. Если вам понадобится перерисовывать все окно или его часть, то используйте способ, который заставляет Windows послать приложению сообщение WM_PAINT:

InvalidateRect (hWnd, 0, TRUE); // Объявляем недейсвительной всю клиентскую область, провоцируя перерисовку окна

Посмотрите справку по этой функции API и уясните смысл ее параметров.

Возвращаемся к проблеме flicker-free drawing

В последней версии нашего приложения в моменты перерисовки содержимого динамического прямоугольника (то есть во время движения мыши при нажатой левой кнопке) мы видим, что изображение мерцает (flickers). Это происходит потому, что рисование производится на глазах у пользователя и он видит эффекты обновления рисунка, а именно: стирания поврежденной области (clip region) и создания нового изображения. Просмотрите код обработки события WM_MOUSEMOVE. Вы видите, что функция рисования

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

работает в контексте hdc, то есть в том контексте, который связан с окном. Эта функция не только рисует контур прямоугольника пунктирным пером, но и закрашивает его внутреннюю область белой кистью. Напомним, что по умолчанию используется кисть цвета WINDOW (этот индекс соответствует белому цвету). Реальные же цвета изменяются в соответствии с включенной растровой операцией R2_NOT.

Если мы хотим, чтобы в процессе перетаскивания изображения, оно непрерывно и плавно перерисовывалось, то нам необходимо:

¨  Отменить закраску внутренности динамического прямоугольника в ветви WM_MOUSEMOVE. Для этого надо убрать два вызова функции Rectangle,

¨  При каждом событии WM_MOUSEMOVE вычислять новое положение изображения, и, не дожидаясь обработки события WM_LBUTTONUP (конец процесса перетаскивания), копировать изображение из контекста hMemDC (в памяти) в контекст hdc (связанный с окном).