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

   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);

  }

  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.

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

Скопируйте весь файл с программой, переименуйте копию в DrawInverse.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);