}
Rectangle (hdc, rTarget.left, rTarget.top, rTarget.right, rTarget.bottom); // Новая мишень
SelectObject (hdc, pOld); // Возвращем перо в контекст устройства
SelectObject (hdc, bOld); // Возвращем кисть
ReleaseDC(hWnd, hdc);
break;
}
case WM_LBUTTONUP: // Реакция на отпускание левой кнопки
ClipCursor (0); // Освобождаем курсор
break;
При закрытии окна следует освобождать динамические ресурсы Windows:
case WM_DESTROY: // Освобождаем ресурсы
DeleteObject (hpenDot);
PostQuitMessage (0);
break;
Функция ClipCursor работает с экранными координатами прямоугольника, который изменяется как при перетаскивании окна, так и при изменении его размеров. Введите код определения и коррекции его координат.
case WM_MOVE:
case WM_SIZE: // Узнаем и преобразовываем координаты клиентской области окна
{
GetClientRect(hWnd, &rClient);
break;
}
Запустите приложение и тщательно проверьте его работу.
¨ Объясните поведение прямоугольника rTarget.
¨ Временно закомментируйте один из вызовов функции Rectangle и объясните поведение прямоугольника.
¨ Временно закомментируйте установку нулевой кисти (и восстановление старой) и объясните поведение.
¨ Пронаблюдайте эффект ограничения движения курсора при нажатой кнопке мыши.
¨ Измените размеры и положение окна на экране и вновь проверьте функционирование как ограничителя курсора, так и динамического прямоугольника.
¨ Поведение динамического прямоугольника мы объяснили ранее. Работает алгоритм: рисуй-стирай.
¨ Отмена нулевой кисти включает кисть по-умолчанию. До этой отмены нулевая кисть не позволяла закрашивать внутренность прямоугольника кистью по-умолчанию. Кисть по-умолчанию—белая, но так как во время закраски действует растровая операция XOR, результат ее применения выглядит черным.
¨ Ограничитель курсора перестает правильно работать потому, что мы не учитываем изменений экранных координат (при изменении позиции всего окна или его размеров). Для коррекции этого недостатка добавьте следующие исправления. Их нужно поместить в общую ветвь обработки сообщений WM_MOVE и WM_SIZE. После этого проверьте работу ограничителя.
POINT ptLT = { rClient.left, rClient.top };
POINT ptRB = { rClient.right, rClient.bottom };
ClientToScreen (hWnd, &ptLT);
ClientToScreen (hWnd, &ptRB);
SetRect (&rClient, ptLT.x, ptLT.y, ptRB.x, ptRB.y);
¨ После обработки события Resize (соответствующего сообщению WM_SIZE) автоматически срабатывает перерисовка поврежденной области окна (clip region). Перед перерисовкой вся поврежденная область автоматически стирается. В результате происходит сбой в последовательности пар: рисуй-стирай. Для коррекции этого дефекта в перерисовке динамического прямоугольника надо скорректировать цепочку парных действий, добавив такую установку (ее местоположение вычислите самостоятельно).
SetRectEmpty (&rTarget);
Для изображения динамического прямоугольника мы выбрали растровую операцию R2_XORPEN и пару инструментов: (пунктирное перо, нулевая кисть). Проверьте работу другой растровой операции (параметра функции SetROP2 — R2_NOT), которая успешно отображает динамический прямоугольник, но без эффекта резинки. Убедитесь, что в этом случае необходима нулевая кисть, а пунктирное перо можно выбросить (объясните).
Для изображения прямоугольника возможно и другое сочетание инструменов и установок: растровая операция R2_NOTXORPEN и пунктирное перо. Нулевая кисть теперь не понадобится, ее наличие не портит картины, но она не нужна. Проверьте этот факт и, рассмотрев булевские операции, объясните его механизм.
Среди множества функций API есть функция DrawFocusRect, которая самостоятельно устанавливает растровую операцию (R2_XORPEN), выбирает пунктирное перо (типа PS_DOT) и нулевую кисть для исключения заливки внутренности прямоугольника. Эта функция значительно упрощает код в ветви обработки WM_MOUSEMOVE.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.