Чтение онлайн

ЖАНРЫ

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

Jenter Алекс

Шрифт:

Итак, чтобы воспользоваться поддержкой масштабирования, которую предоставляет 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имеет следующий прототип:

void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true,

 DWORD dwForceStyle = WS_THICKFRAME | WS_CLIPCHILDREN)

В большинстве случаев на параметры можно не обращать внимание, так как значения по умолчанию вполне удовлетворяют всем нуждам. Параметр bAddGripper указывает, нужно ли добавить к диалогу "гриппер" – маленький уголок, за который можно ухватиться курсором и изменить размеры диалога. Флаг bUseMinTrackSize определяет, нужно ли ограничивать минимальные размеры диалога. В большинстве случаев это хорошая идея, так как сильно уменьшенный дилог всё равно плохо выглядит и не удобен для работы с ним. Минимальный размер диалога хранится в переменной m_ptMinTrackSize, которую ваш класс диалога наследует от класса CDialogResize<>. По умолчанию в неё записывается первоначальный размер диалога (тот, который установлен в момент вызова функции DlgResize_Init). Вы можете записать туда любое другое значение. Что касается параметра dwForceStyle, то это просто стиль, который принудительно назначается диалогу в функции DlgResize_Init.

Ещё одна функция из класса CDialogResize<>, о которой следует упомянуть, – DlgResize_UpdateLayout. Эта функция принудительно пересчитывает координаты всех контролов

в зависимости от переданных ей размеров диалога (cx и cy). Именно она вызывается из обработчика сообщения WM_SIZE, но при необходимости вы можете вызывать её в любом другом месте.

Как составлять карту масштабирования

На самом деле, единственная проблема с классом CDialogResize<> состоит в том, чтобы правильно составить карту масштабирования. Для этого нужно чётко понимать, как работают флаги DLSZ_XXX. Эти флаги по-разному действуют на контрол в группе или без неё.

Сначала посмотрим, как флаги DLSZ_XXX действуют на контрол, не включённый в группу. Допустим, размеры диалога изменились на dx и dy соответственно. Тогда:

• DLSZ_SIZE_X: ширина контрола изменяется на dx.

• DLSZ_SIZE_Y: высота контрола изменяется на dy.

• DLSZ_MOVE_X: контрол двигается вдоль оси x на dx . Флаг DLSZ_SIZE_X при этом игнорируется.

• DLSZ_MOVE_Y: контрол двигается вдоль оси y на dy . Флаг DLSZ_SIZE_Y при этом игнорируется.

Как видно из этого описания, задавать одновременно флаги DLSZ_MOVE_X и DLSZ_SIZE_X (а также DLSZ_MOVE_Y и DLSZ_SIZE_Y) бессмысленно, так как в этом случае будут учитываться только флаги DLSZ_MOVE_*.

Описанная схема масштабирования довольно примитивна. Так, очевидно, что к двум расположенным рядом контролам нельзя применять флаг DLSZ_SIZE_*, так как они оба увеличат размер и "заедут" друг на друга. И всё-таки во многих случаях такого механизма оказывается достаточно. Для примера рассмотрим типичный диалог выбора файла (рисунок 2).

Рисунок 2. Схема диалога открытия файла

При масштабировании логично изменять размер контролов диалога следующим образом: растягивать IDC_LEFT_PANE на всю высоту диалога, растягивать IDC_COMBO по горизонтали, отодвигая IDC_TOOLBAR до предела вправо, отодвигать IDC_NAME и IDC_FILTER вниз и растягивать по горизонтали, перемещать кнопки IDOK и IDCANCEL в правый нижний угол и занимать списком файлов IDC_FILE_LIST всё оставшееся место. Чтобы воплотить в жизнь эту схему, следует записать карту масштабирования следующим образом:

BEGIN_DLGRESIZE_MAP(COpenFileDialog)

 DLGRESIZE_CONTROL(IDC_LEFT_PANE, DLSZ_SIZE_Y)

 DLGRESIZE_CONTROL(IDC_COMBO, DLSZ_SIZE_X)

 DLGRESIZE_CONTROL(IDC_TOOLBAR, DLSZ_MOVE_X)

 DLGRESIZE_CONTROL(IDC_FILE_LIST, DLSZ_SIZE_X | DLSZ_SIZE_Y)

 DLGRESIZE_CONTROL(IDC_NAME, DLSZ_MOVE_Y | DLSZ_SIZE_X)

 DLGRESIZE_CONTROL(IDC_FILTER, DLSZ_MOVE_Y | DLSZ_SIZE_X)

 DLGRESIZE_CONTROL(IDOK, DLSZ_MOVE_Y | DLSZ_MOVE_X)

 DLGRESIZE_CONTROL(IDCANCEL, DLSZ_MOVE_Y | DLSZ_MOVE_X)

END_DLGRESIZE_MAP

Теперь поговорим о контролах, объединённых в группу.

ПРЕДУПРЕЖДЕНИЕ

Реализация групп в WTL подразумевает, что все контролы в группе должны располагаться рядом друг с другом по горизонтали или по вертикали. Флаги, которые вы задаёте для контролов в группе, должны относиться только к одному направлению (или X, или Y), но не к обоим сразу. Несоблюдение этих условий приведёт к странным эффектам. Кроме того, напомню ещё раз, что группы не могут быть вложенными.

Поделиться с друзьями: