Группы обрабатываются следующим образом. Сначала вычисляются координаты огибающего прямоугольника группы , то есть минимального прямоугольника, содержащего все контролы в ней. Далее размеры этого прямоугольника увеличиваются на dx и dy соответственно ( dx и dy имеют то же значение, что и в обсуждении выше). После этого к каждому контролу в группе применяются следующие правила:
• DLSZ_MOVE_X: контрол сдвигается вдоль оси X пропорционально изменению ширины группы (то есть её огибающего прямоугольника).
• DLSZ_MOVE_Y: контрол сдвигается вдоль оси Y пропорционально изменению высоты группы.
• DLSZ_SIZE_X: действует аналогично DLSZ_MOVE_X, но ширина контрола также изменяется пропорционально изменению ширины группы.
• DLSZ_SIZE_Y: действует аналогично DLSZ_MOVE_Y, но высота контрола также изменяется пропорционально изменению высоты группы.
Проиллюстрирую сказанное простым примером. Допустим, у нас есть диалог с тремя расположенными в ряд кнопками. Если написать для него карту масштабирования вида:
BEGIN_DLGRESIZE_MAP(CMyDialog)
BEGIN_DLGRESIZE_GROUP()
DLGRESIZE_CONTROL(IDC_BUTTON1, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_BUTTON2, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_BUTTON3, DLSZ_SIZE_X)
END_DLGRESIZE_GROUP()
END_DLGRESIZE_MAP()
то этот диалог будет масштабироваться следующим образом:
Рисунок 3. Масштабирование с использованием групп
Как это всё работает
Мы не будем надолго задерживаться на внутренней реализации класса CDialogResize<>, так как там нет почти ничего интересного. Когда вы вызываете функцию DlgResize_Init, начальные положения всех контролов в диалоге запоминаются во внутренних структурах WTL. Функция DlgResize_UpdateLayoutиспользует новые размеры диалога и сохранённые ранее координаты контролов, чтобы назначить им новое положение в соответствии с заданными флагами. Что касается карты масштабирования, она просто превращается в статический массив структур _AtlDlgResizeMap, для доступа к которому используется функция GetDlgResizeMap. Структура _AtlDlgResizeMapхранит заданные вами в карте значения:
struct _AtlDlgResizeMap {
int m_nCtlID;
DWORD m_dwResizeFlags;
};
Хочу отметить несколько особенностей реализации класса CDialogResize<>, которые можно использовать в своих целях.
1. Элемент может встречаться в карте масштабирования более одного раза.
2. Элемент, не включённый в группу, двигается относительно его текущего положения.
3. Элемент, включённый в группу, масштабируется с учётом его начального положения (но без учёта его текущей позиции).
Таким образом мы можем, к примеру, отмасштабировать элемент по горизонтали, включив его в группу, а затем отдельно увеличить его высоту. Пример диалога с тремя кнопками, который мы рассмотрели выше, имел один недостаток: при увеличении высоты диалога кнопки не растягивались по вертикали. Теперь мы знаем, как решить эту проблему:
BEGIN_DLGRESIZE_MAP(CMyDialog)
BEGIN_DLGRESIZE_GROUP()
DLGRESIZE_CONTROL(IDC_BUTTON1, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_BUTTON2, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_BUTTON3, DLSZ_SIZE_X)
END_DLGRESIZE_GROUP()
DLGRESIZE_CONTROL(IDC_BUTTON1, DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_BUTTON2, DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_BUTTON3, DLSZ_SIZE_Y)
END_DLGRESIZE_MAP()
Кроме этого, можно включить элемент в несколько групп. Хотя на его местоположение повлияет только последняя группа, этот приём позволит сложным образом влиять на другие контролы. Но не стоит забывать о чувстве меры. Такие приёмы делают вашу программу более запутанной и более медлительной. Нетривиальное масштабирование контролов в диалоге лучше реализовать вручную, а не заниматься неочевидными фокусами с CDialogResize<>.
Контролы
Контролы – ещё один важный элемент операционной системы Windows. Во времена DOS каждому программисту зачастую приходилось изобретать собственный графический интерфейс. Под Windows задача упростилась: хотя сложные нестандартные "фичи" пользовательского интерфейса по-прежнему приходится разрабатывать вручную, в вашем распоряжении всегда есть базовый набор элементов, которые можно использовать для взаимодействия с пользователем или попытаться построить на их основе более сложные контролы.
Библиотека WTL предоставляет программисту классы для удобной работы со стандартными контролами, а также предоставляет средства для расширения их функциональности. Кроме того, в WTL входит несколько нестандартных контролов (кнопка с картинками, гиперссылка и др.), которые вы также можете использовать в приложениях. Рассмотрим все эти классы более подробно.
Читать дальше