Все элементы управления (Control) являются окнами, подчиненными и дочерними (child) по отношению к окну, на котором они располагаются. Система предоставляет готовые классы для ряда элементов управления, таких как кнопки (Button), текстовые поля (Static), поля ввода (Edit) и так далее. Для этих стандартных элементов определены специфичные сообщения и присутствуют оконные процедуры, обрабатывающие эти сообщения. Программы пользователя могут создавать собственные элементы, в этом случае необходимо описать их поведение и, возможно, зарегистрировать соответствующие «пользовательские» сообщения.
Элементы управления должны скрывать от прикладной программы все подробности возникающих с ними элементарных событий (например, движение «мыши» и нажатия ее кнопок). Оконная процедура элемента должна преобразовать их в событие более высокого уровня (например, нажатие кнопки). Естественно, это событие также представляется соответствующим сообщением.
Для унификации и упорядочивания работы с элементами управления каждому из них присваивается собственный идентификатор (он же является и идентификатором дочернего окна). Идентификаторы назначаются произвольно, но должны быть уникальны для каждого элемента. Они передаются окну-родителю как один из параметров сообщений.
Так, элемент «Кнопка» в результате завершенного нажатия генерирует сообщение WM_COMMAND, в параметре wParam которого присутствует идентификатор этого элемента.
Приведенный ниже вызов создает стандартный элемент управления «Кнопка» с заданными именем, координатами, размером и стилем.
hButton = CreateWindow(
"BUTTON", //имя глобального системного класса «Кнопка»
"Btn_Action", //имя кнопки
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, //стиль окна
x, y, width, height, //положение и размер кнопки
hMainWnd, //главное окно
(HMENU)id_Btn_Action, //ID элемента управления
hMainInst, //приложение
NULL
);
В оконной процедуре будет присутствовать проверка поступающих сообщений WM_COMMAND на это значение идентификатора элемента:
switch (uMsg) {
…
case WM_COMMAND:
switch(LOWORD(wParam)) {
…
case id_Btn_Action:
… //обработка нажатия кнопки Btn_Action
break;
…
}
break;
…
}
Непосредственная работа с идентификаторами и сообщениями достаточно трудоёмка, поэтому при программировании сложных интерфейсов целесообразно создавать некоторые средства автоматизации назначения и анализа идентификаторов. Среды программирования обычно предлагают собственные решения для этого, например карты сообщений в Visual Studio.
Для большинства операций, выполняемых с элементами управления (получение и установка параметров, перемещение и так далее) используются специализированные сообщения, поверх которых могут быть предусмотрены «оберточные» функции для более удобного обращения к ним. Сообщения, в зависимости от типа, могут требовать передачи либо через очередь, либо непосредственно в оконную процедуру соответствующего элемента. Список сообщений достаточно велик и различается для каждого вида элементов управления.
Например, следующий вызов заставляет кнопку изменить свое состояние на «нажатое»:
SendMessage(hButton, BM_SETSTATE, (WPARAM)TRUE, 0);
Однако это приводит только к перерисовке самой кнопки, но не к появлению события ее нажатия, которое приходится генерировать отдельно:
PostMessage(hButton, BM_CLICK, 0, 0);
В итоге получаем «программно нажимаемую» кнопку.
Контрольные вопросы
1) Каким образом можно создать на окне такие элементы управления как Edit, Button, ListBox, ComboBox.
2) Каким образом можно получить текст, введенный в Edit и как установить в нем свой собственный текст.
3) Как может быть обработано нажатие на Button.
4) Как можно добавить строки в ListBox и получить выделенную в нем строку.
5) Как можно добавить строки в ComboBox и получить выбранную в нем строку.