struct _AtlUpdateUIData {
WORD m_wState;
void* m_lpData;
};
Теперь понятно, что делают функции типа UIEnableи UISetCheck. Они просто изменяют поля структуры _AtlUpdateUIData, соответствующей заданному элементу. Что касается семейства функций UIUpdateXXX, то они используют данные из m_pUIData, чтобы обновить элементы управления.
Наконец, переменная m_wDirtyTypeиспользуется в целях оптимизации. В ней содержатся типы тех элементов, состояние которых было изменено с момента последнего обновления. Когда вы вызываете функцию UIUpdateXXX, WTL проверяет соответствующий флаг в m_wDirtyTypeи обновляет элементы, только если он установлен. После обновления m_wDirtyTypeсбрасывается в ноль.
Где обновлять элементы
Механизм обновления элементов пользовательского интерфейса, реализованный в WTL, не навязывает вам определённой стратегии обновления, а просто избавляет вас от рутинной работы. Вы можете обновлять элементы всякий раз, когда пользователь делает какое-то действие. В этом случае по всей программе будут разбросаны "пачки" вызовов функций обновления UIEnable, UISetTextи т. д. Но совершенно очевидно, что такой подход раздувает и запутывает ваш код. Гораздо лучше написать одну функцию, которая обновляет все элементы в зависимости от текущего состояния программы. Потом к этой функции можно обращаться всякий раз, когда состояние элементов может измениться.
Альтернативный вариант, который, кстати, используется в MFC, заключается в обновлении элементов в фоне, то есть когда очередь сообщений пуста. Если вы используете немодальный диалог, вам будет нетрудно реализовать эту идею и в WTL: для этого достаточно зарегистрировать объект диалога в цикле сообщений как фоновый обработчик, а затем обновлять элементы в функции OnIdle. Однако если диалог модальный, цикл сообщений скрыт внутри функции DialogBoxParamи фоновая обработка в стиле wtl недоступна. В этом случае можно использовать сообщение WM_ENTERIDLE(модальный диалог посылает его родительскому окну, когда очередь сообщений исчерпана) или вообще отказаться от фоновой обработки.
[ ПРОДОЛЖЕНИЕ СЛЕДУЕТ ]
Это все на сегодня. Пока!
Алекс Jenter jenter@rsdn.ru Duisburg, 2001. Публикуемые в рассылке материалы принадлежат сайту RSDN.
Программирование на Visual C++
Выпуск №55 от 18 ноября 2001 г.
Добрый день!
Сегодня в выпуске – продолжение второй части статьи "Использование WTL".
Если вы еще не читали первую часть, ее можно найти на RSDN.
СТАТЬЯ
Использование WTL
Часть 2. Диалоги и контролы (продолжение)
Класс CDialogResize<>: масштабирование диалогов в стиле WTL
Как известно, обычные диалоги не позволяют себя масштабировать. С точки зрения пользователя это довольно неудобно. Часть информации не помещается в маленьких контролах, и их приходится прокручивать, чтобы просмотреть всё целиком. В то же время часть экрана монитора всё равно остаётся незанятой, и диалог вполне мог бы её занять. Возникает вопрос: как реализовать масштабируемые диалоги в вашем приложении?
Обычно эта проблема решается так. Диалогу назначается стиль WS_THICKFRAME( Border: resizing в редакторе ресурсов). Затем в программе перехватывается сообщение WM_SIZE, сигнализирующее об изменении размеров диалога. В ответ на него программа соответствующим образом изменяет размеры контролов в диалоге. Этот подход универсален и достаточно прост в реализации, но требует написания большого количества кода, связанного с пересчётом координат. Поэтому в WTL введён класс, который в ряде случаев избавит вас от рутинной работы по масштабированию контролов. Этот класс называется CDialogResize<>. Он описан в файле atlframe.h . Хотя этот класс не является универсальным, он подойдёт в большинстве случаев. Замечу, что его можно применять с любым окном, содержащим дочерние окна, но чаще всего он применяется именно с диалогами.
Итак, чтобы воспользоваться поддержкой масштабирования, которую предоставляет WTL, нужно включить в число базовых классов вашего диалога класс CDialogResize<>, задав в качестве параметра шаблона имя порождаемого класса. После этого вам, как обычно, потребуется написать карту – на этот раз карту масштабирования. Макросы, из которых она формируется, приведены в таблице 4.
Макрос |
Описание |
BEGIN_DLGRESIZE_MAP(thisClass) |
Начало карты масштабирования. thisClass– имя класса, в котором содержится карта. |
END_DLGRESIZE_MAP() |
Этот макрос завершает карту масштабирования. |
DLGRESIZE_CONTROL(id, flags) |
Этот макрос определяет, каким образом должен масштабироваться контрол с идентификатором id. Для этого в WTL определено несколько флагов, которые нужно объединить операцией логического "ИЛИ" и передать в качестве второго параметра макроса flags. Вы можете использовать флаги DLSZ_MOVE_Xи DLSZ_MOVE_Y(перемещение вдоль осей X и Y соответственно), DLSZ_SIZE_Xи DLSZ_SIZE_Y(изменение ширины и высоты контрола), а также флаг DLSZ_REPAINT, если после масштабирования контрола его нужно перерисовывать (то есть вызывать для него функцию Invalidate). |
BEGIN_DLGRESIZE_GROUP() |
Контролы, включённые в карту масштабирования, можно группировать. Об эффектах группировки мы поговорим позже. Макрос BEGIN_DLGRESIZE_GROUPначинает группу контролов. Группы не могут быть вложенными. |
END_DLGRESIZE_GROUP() |
Завершает группу контролов. Каждому макросу BEGIN_DLGRESIZE_GROUPдолжен соответствовать ровно один макрос END_DLGRESIZE_GROUP. |
Кроме написания карты масштабирования, необходимо выполнить ещё два действия. Во-первых, класс CDialogResize<>имеет свою собственную карту сообщений. В частности, она содержит обработчик сообщения WM_SIZE, который инициирует перемасштабирование контролов при каждом изменении размеров диалога. Эту карту сообщений следует подключить к карте сообщений вашего диалога, используя макрос CHAIN_MSG_MAP:
Читать дальше