- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Программирование на Visual C++. Архив рассылки - Алекс Jenter
Шрифт:
Интервал:
Закладка:
В основе механизма owner draw лежат сообщения WM_DRAWITEM, WM_MEASUREITEM, WM_COMPAREITEM и WM_DELETEITEM. Так, в обработчике WM_DRAWITEM выполняется собственно отрисовка контрола, а в обработчике WM_MEASUREITEM – задание размеров отдельных элементов, содержащихся в контроле (пунктов меню, элементов списка и т.п.). WTL содержит небольшой класс COwnerDraw<>, который помогает вам обрабатывать все эти сообщения (описан в файле atlframe.h). Чтобы им воспользоваться, включите его в список базовых классов окна, которое будет заниматься отрисовкой контролов.
Посмотрим, какие элементы входят в класс COwnerDraw<>. В первую очередь это карта сообщений. Точнее, две карты (вы ещё не забыли, что в WTL окно может иметь несколько карт сообщений?).
BEGIN_MSG_MAP(COwnerDraw<T>)
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<IDD_BUTTON_DIALOG>, public COwnerDraw<CButtonDemoDlg>, ... {
private:
HICON m_hIcon1, m_hIcon2;
...
public:
BEGIN_MSG_MAP(CButtonDemoDlg)
...
CHAIN_MSG_MAP(COwnerDraw<CButtonDemoDlg>)
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").
В WTL есть класс CCustomDraw<> (описан в файле atlctls.h), который помогает вам перехватывать уведомление NM_CUSTOMDRAW и распаковывать его параметры. Он очень похож на класс COwnerDraw<>, который мы рассмотрели выше. Его реализация выглядит так.
template <class T> class CCustomDraw {
public:
// Message map and handlers
BEGIN_MSG_MAP(CCustomDraw<T>)
NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
ALT_MSG_MAP(1)
REFLECTED_NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
END_MSG_MAP()
// message handler
LRESULT OnCustomDraw(int idCtrl, LPNMHDR pnmh, BOOL& bHandled) {
T* pT = static_cast<T*>(this);
pT->SetMsgHandled(TRUE);
LPNMCUSTOMDRAW lpNMCustomDraw = (LPNMCUSTOMDRAW)pnmh;
DWORD dwRet = 0;
switch(lpNMCustomDraw->dwDrawStage) {
case CDDS_PREPAINT:
dwRet = pT->OnPrePaint(idCtrl, lpNMCustomDraw);
break;
case CDDS_POSTPAINT:
dwRet = pT->OnPostPaint(idCtrl, lpNMCustomDraw);
break;
// Остальные фазы отрисовки
// ...
default:
pT->SetMsgHandled(FALSE);
break;
}
bHandled = pT->IsMsgHandled();
return dwRet;
}
// Overrideables
DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) {
return CDRF_DODEFAULT;
}
DWORD OnPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) {
return CDRF_DODEFAULT;
}
// Остальные функции.
// ...
Как видим, в классе CCustomDraw<> также предусмотрено две карты сообщений – для родительского окна и для самого контрола, если он получает отражённые уведомления. Обработчик OnCustomDraw распаковывает параметры уведомления NM_CUSTOMDRAW и определяет фазу рисования. Каждой фазе соответствует своя функция, которая и вызывается из OnCustomDraw. Вы можете переопределить любую из этих функций в производном классе и включить в неё нужный вам код (реализации из класса CCustomDraw<> не выполняют никой полезной работы). Список фаз рисования и соответствующих им функций приведён в таблице 10.
Фаза Прототип функции CDDS_PREPAINTD WORD OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw) CDDS_POSTPAINTD WORD OnPostPaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw) CDDS_PREERASAED WORD OnPreErase(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw) CDDS_POSTERASED WORD OnPostErase(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw) CDDS_ITEMPREPAINTD WORD OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw) CDDS_ITEMPOSTPAINTD WORD OnItemPostPaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw) CDDS_ITEMPREERASED WORD OnItemPreErase(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw) CDDS_ITEMPOSTERASE DWORD OnItemPostErase(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw)Вот небольшой пример использования класса CCustomDraw<>. Для разнообразия я поручил обработку сообщения NM_CUSTOMDRAW самому контролу. Подразумевается, что родительское окно переправляет ему уведомления, используя механизм отражения.
class CCustomDrawListView : public CWindowImpl<CCustomDrawListView, CListViewCtrl>, public CCustomDraw<CCustomDrawListView> {
public:
BEGIN_MSG_MAP(CCustomDrawListView)
// Направляем сообщения в карту №1 класса CCustomDraw!
CHAIN_MSG_MAP_ALT(CCustomDraw<CCustomDrawListView>, 1)
END_MSG_MAP()
DWORD OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw) {
// Запрашиваем уведомления NM_CUSTOMDRAW для каждого элемента списка.
return CDRF_NOTIFYITEMDRAW;
}
DWORD OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw) {
// Нам нужны поля, специфичные для ListView.
LPNMLVCUSTOMDRAW pLVCD = (LPNMLVCUSTOMDRAW)lpNMCustomDraw;
if ((lpNMCustomDraw->dwItemSpec & 0x01) != 0) {
// Для нечётных элементов: рисуем белым по чёрному.
pLVCD->clrText = RGB(255,255,255);
pLVCD->clrTextBk = RGB(0,0,0);
} else {
// Для чётных элементов: рисуем красным по серому.
pLVCD->clrText = RGB(255,0,0);
pLVCD->clrTextBk = RGB(200,200,200);
}
return CDRF_NEWFONT;
}
};
От теории к практикеМы изучили уже целую кучу новых классов, и теперь самое время посмотреть, как они применяются на практике. В этом разделе мы изучим целый ряд демонстрационных программ, иллюстрирующих различные аспекты программирования диалогов и контролов с использованием библиотеки WTL.
WTLErrLook: приложение на базе модального диалогаДемонстрационный проект WTLErrLook
WTLErrLook