Категории
Самые читаемые
RUSBOOK.SU » Компьютеры и Интернет » Программирование » Программирование на Visual C++. Архив рассылки - Алекс Jenter

Программирование на Visual C++. Архив рассылки - Алекс Jenter

Читать онлайн Программирование на Visual C++. Архив рассылки - Алекс Jenter

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 94 95 96 97 98 99 100 101 102 ... 156
Перейти на страницу:

Функции, которые мы только что рассмотрели, не изменяют фактическое состояние элементов. Они только записывают новые значения во внутренние структуры класса CUpdateUI<>. Чтобы внесённые изменения вступили в силу, нужно вызвать специальную функцию. Для каждого типа контейнеров существует своя функция: UIUpdateMenuBar для меню, UIUpdateToolBar для панели инструментов, UIUpdateStatusBar для строки состояния и UIUpdateChildWindows для контейнера дочерних окон. Каждая из этих функций принимает флаг bForceUpdate. Используйте его, чтобы принудительно обновить все элементы, прописанные в карте UI.

Как это всё работает

Посмотрим, как устроен класс CUpdateUI<>. Карта UI, которую вы создаёте, превращается в массив структур _AtlUpdateUIMap.

struct _AtlUpdateUIMap {

 WORD m_nID;

 WORD m_wType;

};

Каждая структура содержит в точности те значения, которые вы передаёте макросу UPDATE_ELEMENT в качестве параметров. Массив завершается структурой со значениями {(WORD)-1, 0}. Для обращения к нему используется функция GetUpdateUIMap, внутри которой он описывается как статическая переменная. Этот массив один на все объекты класса, порождённого от CUpdateUI<>. Кроме этого, каждый объект класса наследует от CUpdateUI<> переменные m_UIElements, m_pUIData и m_wDirtyType.

m_UIElements — это массив контейнеров, для редактирования которого и используется семейство функций UIAddXXX. Кстати, странно, что разработчики WTL не предусмотрели средства для удаления контейнеров из этого массива. Но тут уже ничего не поделаешь.

m_pUIData — массив структур _AtlUpdateData. Количество элементов в этом массиве в точности соответствует количеству записей в карте UI. Каждая структура _AtlUpdateData содержит флаги состояния (те самые, которые меняет функция UISetState) и указатель на строку, которые должны быть назначены элементу. Место для строк распределяется динамически. Вот как описана структура _AtlUpdateUIData.

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 [email protected] 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:

BEGIN_MSG_MAP(CMyDialog)

 ...

 CHAIN_MSG_MAP(CDialogResize<CMyDialog>)

 ...

END_MSG_MAP()

Во вторых, после того, как ваш дилог создан, необходимо инициализировать внутренние структуры WTL, связанные с масштабированием. Это делается при помощи функции DlgResize_Init. Удобно вызывать её из обработчика сообщения WM_INITDIALOG. Функция DlgResize_Initимеет следующий прототип:

1 ... 94 95 96 97 98 99 100 101 102 ... 156
Перейти на страницу:
На этой странице вы можете бесплатно скачать Программирование на Visual C++. Архив рассылки - Алекс Jenter торрент бесплатно.
Комментарии
Открыть боковую панель
Комментарии
Сергій
Сергій 25.01.2024 - 17:17
"Убийство миссис Спэнлоу" от Агаты Кристи – это великолепный детектив, который завораживает с первой страницы и держит в напряжении до последнего момента. Кристи, как всегда, мастерски строит