Все элементы управления (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, получение доступа к выбранной в нем строке.
Задание
Написать программу, которая создает окно с двумя элементами управления ListBox, одним Edit и четырьмя Button («Add», «Clear», «ToRight» и «Delete»). При нажатии на кнопку «Add» текст из Edit должен добавляться в первый ListBox, если такого текста там еще нет (необходимо выполнить проверку). Нажатие кнопки «Clear» очищает оба ListBox-а. Нажатие кнопки «ToRight» копирует выделенную строку из первого ListBox во второй (если там еще нет такой строки). Нажатие кнопки «Delete» удаляет выделенные строки в каждом из ListBox-ов.
Лабораторная работа №8
Графический ввод-вывод в оконном приложении
Цели работы:
1) изучить графическую подсистему GDI.
2) научиться использовать графику GDI.