void LengthyOperation() {
// Конструктор объекта waitCur вызовет метод Set, и курсор поменяется на "песочные часы".
CWaitCursor waitCur;
// Выполняем длительную операцию.
…
// Здесь вызывается деструктор для объекта waitCur, и курсор восстанавливается.
}
Класс COwnerDraw<>: отрисовка контрола родительским окном в стиле WTL
Механизм отрисовки контрола родительским окном (owner draw) появился довольно давно – ещё в Windows 3.0. Он позволяет придать контролу совершенно произвольный внешний вид. Его поддерживают такие стандартные элементы управления, как кнопка, меню, простой список и комбинированный список.
В основе механизма owner draw лежат сообщения WM_DRAWITEM, WM_MEASUREITEM, WM_COMPAREITEMи WM_DELETEITEM. Так, в обработчике WM_DRAWITEMвыполняется собственно отрисовка контрола, а в обработчике WM_MEASUREITEM– задание размеров отдельных элементов, содержащихся в контроле (пунктов меню, элементов списка и т.п.). WTL содержит небольшой класс COwnerDraw<>, который помогает вам обрабатывать все эти сообщения (описан в файле atlframe.h ). Чтобы им воспользоваться, включите его в список базовых классов окна, которое будет заниматься отрисовкой контролов.
Посмотрим, какие элементы входят в класс COwnerDraw<>. В первую очередь это карта сообщений. Точнее, две карты (вы ещё не забыли, что в WTL окно может иметь несколько карт сообщений?).
BEGIN_MSG_MAP(COwnerDraw)
MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem)
MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem)
ALT_MSG_MAP(1)
MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem)
MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem)
MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem)
END_MSG_MAP()
По умолчанию используется карта с номером 0. Она обрабатывает сообщения в родительском окне. Карту с номером 1 можно использовать для перехвата отражённых сообщений, связанных с механизмом owner draw, в самом контроле.
Обработчики сообщений реализованы примерно одинаково. Они распаковывают параметры сообщений и передают управление специальным функциям, которые и выполняют основную работу. Вот прототипы этих функций.
void DrawItem(LPDRAWITEMSTRUCT);
void MeasureItem(LPMEASUREITEMSTRUCT);
int CompareItem(LPCOMPAREITEMSTRUCT);
void DeleteItem(LPDELETEITEMSTRUCT);
Именно эти функции вы можете переопределить в производном классе, чтобы реализовать отрисовку контрола. Это удобнее, чем вручную перехватывать сообщения и вспоминать, каким образом в их параметрах запакована информация. Обратите внимание, что класс COwnerDraw<>содержит стандартную реализацию этих функций. Функции DrawItem, CompareItemи DeleteItemничего полезного не делают, зато функция MeasureItemвозвращает размер пункта меню в зависимости от настроек системы и размер элемента в списке в зависимости от размера стандартного системного фонта, который используется в диалогах и меню. Если такое поведение вас не устраивает, измените его на любое другое.
Рассмотрим пример использования класса COwnerDraw<>для рисования нестандартной кнопки.
class CButtonDemoDlg : public CSimpleDialog, public COwnerDraw, ... {
private:
HICON m_hIcon1, m_hIcon2;
...
public:
BEGIN_MSG_MAP(CButtonDemoDlg)
...
CHAIN_MSG_MAP(COwnerDraw)
END_MSG_MAP()
void DrawItem(LPDRAWITEMSTRUCT pDIS) {
if ((pDIS->itemState & ODS_SELECTED) != 0) {
// Кнопка нажата
DrawIcon(pDIS->hDC, 0, 0, m_hIcon2);
} else {
// Кнопка отпущена
DrawIcon(pDIS->hDC, 0, 0, m_hIcon1);
}
}
};
Класс CCustomDraw<>: пользовательское рисование в стиле WTL
Механизм пользовательского рисования (custom draw) иногда путают с owner draw. Он предназначен для той же цели – изменить внешний вид контролов. Однако он появился несколько позже (вместе с набором общих контролов из библиотеки comctl32.dll ) и используется для более новых контролов (таких, как ListView и TreeView).
Пользовательское рисование работает следующим образом. Когда контрол перерисовывается, он посылает родительскому окну одно или несколько уведомлений NM_CUSTOMDRAW, упакованных в сообщение WM_NOTIFY. Каждое уведомление соответствует некоторой фазе перерисовки (до/после рисования контрола целиком или отдельного элемента и т. д.). Фазу можно определить по полю dwDrawStageструктуры NMCUSTOMDRAW, указатель на которую передаётся вместе с уведомлением. В зависимости от фазы родительское окно может выполнить некоторые действия (например, изменить цвет или фонт отдельного элемента списка). Подробности можно найти в MSDN (см. статью "Customizing a Control's Appearance Using Custom Draw").
Читать дальше