- Практическое руководство. Обработка события нажатия кнопки в Windows Forms How to: Respond to Windows Forms Button Clicks
- Реагирование на нажатие кнопки To respond to a button click
- Операционная система Microsoft Windows 3.1 для программиста
- 2.1. Кнопки
- Создание кнопки
- Сообщение WM_COMMAND
- Приложение BUTTON
- Управление кнопкой из приложения
- Вызов функций управления окном
- Передача сообщений органу управления
- Сообщения для кнопки
- Приложение BUTNCTL
- Переключатели
- Кнопки, которые рисует родительское окно
- Приложение OWNBUT
- Кнопки и клавиатура
Практическое руководство. Обработка события нажатия кнопки в Windows Forms How to: Respond to Windows Forms Button Clicks
Самым простым использованием Button элемента управления Windows Forms является выполнение некоторого кода при нажатии кнопки. The most basic use of a Windows Forms Button control is to run some code when the button is clicked.
При щелчке Button элемента управления также создается ряд других событий, таких как MouseEnter события, MouseDown и MouseUp . Clicking a Button control also generates a number of other events, such as the MouseEnter, MouseDown, and MouseUp events. Если вы планируете присоединить обработчики событий для этих связанных событий, убедитесь, что их действия не конфликтуют. If you intend to attach event handlers for these related events, be sure that their actions do not conflict. Например, если нажать кнопку, чтобы очистить сведения, введенные пользователем в текстовое поле, при наведении указателя мыши на кнопку не должно отображаться всплывающая подсказка с несуществующими сведениями. For example, if clicking the button clears information that the user has typed in a text box, pausing the mouse pointer over the button should not display a tool tip with that now-nonexistent information.
Если пользователь пытается дважды щелкнуть Button элемент управления, каждый щелчок будет обрабатываться отдельно, то есть элемент управления не поддерживает событие двойного щелчка. If the user attempts to double-click the Button control, each click will be processed separately; that is, the control does not support the double-click event.
Реагирование на нажатие кнопки To respond to a button click
В этой кнопке Click EventHandler напишите код для выполнения. In the button’s Click EventHandler write the code to run. Button1_Click должен быть привязан к элементу управления. Button1_Click must be bound to the control. Дополнительные сведения см. в разделе инструкции. Создание обработчиков событий во время выполнения для Windows Forms. For more information, see How to: Create Event Handlers at Run Time for Windows Forms.
Операционная система Microsoft Windows 3.1 для программиста
2.1. Кнопки
Для создания кнопки, как мы уже говорили, ваше приложение должно создать дочернее окно на базе предопределенного класса «button». После этого родительское окно будет получать от кнопки сообщение с кодом WM_COMMAND. Этим сообщением кнопка информирует родительское окно о том, что с ней что-то сделали, например, нажали.
Создание кнопки
Для создания кнопки вам надо вызвать функцию CreateWindow. Мы уже рассказывали вам об этой функции в предыдущем томе. С помощью нее мы создавали окна во всех наших приложениях. Для удобства приведем прототип функции CreateWindow еще раз:
Параметр функции lpszClassName — указатель на строку, содержащую имя класса, на базе которого создается окно. Для создания кнопки необходимо указать имя класса «button».
Параметр функции lpszWindowName — указатель на строку, содержащую заголовок окна (Title Bar). Эта строка будет написана на кнопке.
Параметр dwStyle — стиль создаваемого окна. Этот параметр задается как логическая комбинация отдельных битов. Для кнопки следует задать стиль как комбинацию констант WS_CHILD, WS_VISIBLE и константы, определяющей один из возможных стилей кнопки.
Парамеры x и y функции CreateWindow определяют горизонтальную (x) и вертикальную (y) координату кнопки относительно верхнего левого угла родительского окна.
Параметры nWidth и nHeight определяют, соответственно, ширину и высоту создаваемой кнопки.
Параметр hwndParent определяет идентификатор родительского окна, на поверхности которого создается кнопка.
Параметр hmenu — идентификатор меню или идентификатор порожденного (child) окна. Для каждого создаваемого вами дочернего окна вы должны определить собственный идентификатор. Родительское окно будет получать от дочерних окон сообщения. При помощи идентификатора дочернего окна функция родительского окна сможет определить дочернее окно, пославшее сообщение родительскому окну.
Параметр hinst — идентификатор приложения, которое создает окно. Необходимо использовать значение, передаваемое функции WinMain через параметр hInstance.
Последний параметр функции (lpvParam) представляет собой дальний указатель на область данных, определяемых приложением. Этот параметр передается в функцию окна вместе с сообщением WM_CREATE при создании окна. Для кнопки вы должны указать значение NULL.
Для создания кнопки с надписью «Help» в точке с координатами (10, 30) и размерами (40, 20) можно использовать, например, такой вызов функции CreateWindow:
Стиль кнопки влияет на ее внешний вид и поведение:
Стиль кнопки | Внешний вид | Описание |
BS_3STATE | Переключатель, который может находится в одном из трех состояний: включенном (квадратик перечеркнут), выключенном (квадратик не перечеркнут), неактивном (квадратик отображается серым цветом) | |
BS_AUTO3STATE | Аналогично стилю BS_3STATE, но внешний вид кнопки изменяется автоматически при ее переключении | |
BS_AUTOCHECKBOX | Переключатель, который может находиться в одном из двух состояний: включенном или выключенном. Внешний вид кнопки изменяется автоматически при ее переключении | |
BS_AUTORADIOBUTTON | Переключатель, который может находиться в одном из двух состояний: включенном (внутри окружности имеется жирная черная точка) или выключенном (окружность не закрашена). Внешний вид кнопки изменяется автоматически при ее переключении | |
BS_CHECKBOX | Переключатель, который может находиться в одном из двух состояний: включенном или выключенном. | |
BS_DEFPUSHBUTTON | Стандартная кнопка с толстой рамкой вокруг | |
BS_GROUPBOX | Прямоугольная область, внутри которой могут находиться другие кнопки. Обычно используется в диалоговых панелях. Этот орган управления не воспринимает сообщения от мыши или клавиатуры | |
BS_LEFTTEXT | Этот стиль указывается вместе с другими и означает, что текст, расположенный около кнопки, должен находиться слева, а не справа от кнопки | |
BS_OWNERDRAW | Внешний вид определяется родительским окном | Внешний вид кнопки определяется родительским окном, которое само рисует кнопку во включенном, выключенном или неактивном состоянии |
BS_PUSHBUTTON | Стандартная кнопка без рамки | |
BS_RADIOBUTTON | Переключатель, который может находиться в одном из двух состояний: включенном или выключенном. | |
BS_USERBUTTON | Внешний вид определяется родительским окном | Устаревший стиль, аналогичный по назначению стилю BS_OWNERDRAW. Не рекомендуется к использованию. Этот стиль не описан в документации SDK для Windows версии 3.1, но определен в файле windows.h |
Некоторые стили кнопок, описанные в этой таблице, используются для создания переключателей. Переключатели мы рассмотрим позже.
Таким образом, указав функции CreateWindow класс окна «button», мы создаем кнопку. Но с помощью класса «button» можно реализовать несколько перечисленных видов кнопок. Для уточнения вида кнопки мы дополнительно в стиле окна определяем стиль кнопки, указывая константу с префиксом имени BS_. За исключением константы BS_LEFTTEXT, допустимо указывать только одну из перечисленных выше констант. Константа BS_LEFTTEXT используется совместно с другими стилями кнопок, как правило, при создании кнопок в виде переключателей с текстом, расположенным слева от квадратика или кружка переключателя.
Сообщение WM_COMMAND
Сообщение с кодом WM_COMMAND передается функции родительского окна от органа управления, созданного этим окном. При создании органа управления (например, кнопки на базе класса «button») вы вызываете функцию CreateWindow, которой указываете идентификатор родительского окна и идентификатор органа управления.
Если орган управления изменяет свое состояние (например, когда вы нажали на кнопку), функция родительского окна получает сообщение WM_COMMAND. Вместе с этим сообщением функция родительского окна получает в параметре wParam идентификатор органа управления. Младшее слово параметра lParam содержит идентификатор дочернего окна, т. е. идентификатор окна органа управления. Старшее слово содержит код извещения от органа управления (notification code), по которому можно судить о том, какое действие было выполнено над органом управления.
Когда вы нажимаете на кнопку, родительское окно получает сообщение WM_COMMAND с кодом извещения, равным BN_CLICKED. Получив такое сообщение, приложение определяет, что была нажата кнопка, идентификатор которой находится в параметре wParam.
При использовании кнопки устаревшего стиля BS_USERBUTTON функция родительского окна может получить сообщения с кодами извещения BN_DISABLE, BN_DOUBLECLICKED, BN_HLITE, BN_PAINT, BN_UNHILITE. В новых приложениях эти коды извещения не используются.
Орган управления BS_GROUPBOX не обрабатывает сообщения от мыши или клавиатуры и не посылает в родительское окно сообщение WM_CONTROL. Он используется в качестве объединяющей рамки с заголовком, внутри которой располагаются другие органы управления, такие как кнопки или переключатели.
Приложение BUTTON
Приложение BUTTON демонстрирует способ создания стандартных кнопок и обработку сообщений от них. В главном окне приложения создается две кнопки с названием «Button 1» и «Button 2». Если нажать на одну из них, на экране появится диалоговая панель с сообщением о номере нажатой кнопки (рис. 2.1).
Рис. 2.1. Главное окно приложения BUTTON
Главный файл приложения BUTTON приведен в листинге 2.2.
Листинг 2.1. Файл button\button.cpp
Файл определения модуля приложения приведен в листинге 2.2.
Листинг 2.2. Файл button\button.def
В начале главного файла приложения определены идентификаторы двух создаваемых кнопок:
Функция главного окна будет использовать эти идентификаторы для того чтобы различать кнопки. В этих определениях вы можете использовать произвольные численные значения.
После создания и вывода на экран главного окна приложения функция WinMain создает кнопки, вызывая функцию CreateWindow:
Для первой кнопки указывается предопределенный класс окна ‘button», заголовок «Button 1», стиль кнопки BS_PUSHBUTTON, расположение, размеры, а также идентификатор кнопки IDB_Button1.
Вторая кнопка создается аналогично. Она имеет те же размеры, но расположена ниже, имеет заголовок «Button 2» и идентификатор IDB_Button2.
В функции окна добавился обработчик сообщения WM_COMMAND. Это сообщение поступает в функцию окна, когда вы нажимаете любую из двух созданных кнопок. Обработчик анализирует идентификатор кнопки, передаваемый вместе с сообщением в параметре wParam, и выводит соответствующее сообщение:
Управление кнопкой из приложения
У вас есть две возможности управления кнопкой из приложения Windows (или другим органом управления). Во-первых, вы можете, вызывая специальные функции, динамически перемещать орган управления, делать его активным или неактивным, скрывать его или отображать в окне. Во-вторых, кнопке или другому органу управления (как и большинству объектов Windows) можно посылать сообщения, в ответ на которые этот орган будет выполнять различные действия.
Вызов функций управления окном
Для перемещения органа управления внутри окна можно воспользоваться функцией MoveWindow, описанной нами ранее. Функция MoveWindow определяет новое расположение и размеры окна:
Параметр hwnd указывает идентификатор перемещаемого окна. Для перемещения органа управления вам необходимо указать его идентификатор, полученный от функции CreateWindow.
Параметр nLeft указывает новую координату левой границы окна, параметр nTop — новую координату нижней границы окна. Эти параметры определяют новое положение органа управления в системе координат, связанной с родительским окном. Напомним, что при перемещении обычного перекрывающегося (overlapped) или временного (pop-up) окна используется экранная система координат.
Параметры nWidth и nHeight определяют, соответственно, ширину и высоту окна. Если при перемещении органа управления необходимо сохранить его размеры, укажите значения, использованные при создании этого органа управления.
Последний параметр fRepaint представляет собой флаг, определяющий, надо ли перерисовывать окно после его перемещения. Если значение этого параметра равно TRUE, функция окна после перемещения окна получит сообщение WM_PAINT. Если указать это значение как FALSE, никакая часть окна не будет перерисована. При перемещении органа управления в качестве этого параметра следует указать TRUE.
Иногда возникает необходимость заблокировать орган управления. Например, если в данный момент времени или в данной конфигурации программных или аппаратных средств некоторый режим работы приложения недоступен, имеет смысл заблокировать орган управления, включающий такой режим. Это позволит уберечь пользователя от ошибочного включения режима. Использование недоступного режима может закончиться для него в лучшем случае получением предупреждающего сообщения.
Для блокирования и разблокирования органа управления следует пользоваться функцией EnableWindow:
Функция EnableWindow позволяет разрешать или запрещать поступление сообщений от клавиатуры или мыши в окно или орган управления, идентификатор которого задан параметром hWnd.
Параметр fEnable определяет, будет ли указанное окно заблокировано или наоборот, разблокировано. Для того чтобы заблокировать окно (или орган управления) необходимо для этого парамера указать значение FALSE. Если надо разблокировать окно, используйте значение TRUE.
В любой момент времени приложение может определить, является ли окно или орган управления заблокированным или нет. Для этого следует использовать функцию IsWindowEnabled:
В качестве единственного параметра этой функции надо указать идентификатор проверяемого окна или органа управления. Для заблокированного окна функция возвращает значение FALSE, для разблокированного — TRUE.
Можно вообще убрать орган управления из окна, скрыв его при помощи функции ShowWindow:
Функция отображает окно, идентификатор которого задан параметром hwnd, в нормальном, максимально увеличенном или уменьшенном до пиктограммы виде, в зависимости от значения параметра nCmdShow. Если использовать эту функцию для органа управления, вы можете его скрыть, указав в параметре nCmdShow значение SW_HIDE.
Для восстановления органа управления надо вызвать эту функцию с параметром SW_SHOWNORMAL.
Можно изменить текст, написанный на кнопке. Для этого следует использовать функцию SetWindowText:
Эта функция устанавливает новый текст для заголовка окна (или органа управления), идентификатор которого указан при помощи параметра hWnd. Параметр lpszString является дальним указателем на строку символов, закрытую двоичным нулем, которая будет использована в качестве нового заголовка.
И, наконец, вы можете уничтожить созданный вами орган управления. Для этого следует вызвать функцию DestroyWindow:
Функция DestroyWindow уничтожает окно, идентификатор которого задан в качестве параметра hWnd, и освобождает все связанные с ним ресурсы.
Возвращаемое значение равно TRUE в случае успеха или FALSE при ошибке.
Передача сообщений органу управления
В операционной системе Windows широко используется практика передачи сообщений от одного объекта к другому. Приложение BUTTON демонстрирует передачу сообщения WM_COMMAND от кнопки родительскому окну, создавшему эту кнопку. Однако родительское окно может само послать сообщение кнопке или любому другому органу управления, если оно знает его идентификатор.
Существует два способа передачи сообщений.
Первый способ — запись сообщения в очередь приложения. Он основан на использовании функции PostMessage:
Функция PostMessage помещает сообщение в очередь сообщений для окна, указанного параметром hWnd, и сразу возвращает управление. Возвращаемое значение равно TRUE в случае успешной записи сообщения в очередь или FALSE при ошибке. Записанное при помощи функции PostMessage сообщение будет выбрано и обработано в цикле обработки сообщений.
Параметр uMsg задает идентификатор передаваемого сообщения. Параметры wParam и lParam используются для передачи параметров сообщения.
Второй способ — непосредственная передача сообщения функции окна минуя очередь сообщений. Этот способ реализуется функцией SendMessage:
Параметры функции SendMessage используются аналогично параметрам функции PostMessage. Но в отличие от последней функция SendMessage вызывает функцию окна и возвращает управление только после возврата из функции окна.
Возвращаемое функцией SendMessage значение зависит от обработчика сообщения в функции окна.
Сообщения для кнопки
Для управления кнопкой вы можете использовать сообщение BM_SETSTATE, которое позволяет установить кнопку в нажатое или отжатое состояние.
Для установки кнопки в нажатое состояние следует передать ей сообщение BM_SETSTATE с параметром wParam, равным TRUE, и lParam, равным 0:
Для возврата кнопки в исходное состояние передайте ей то же самое сообщение, но с параметром wParam, равным FALSE:
Приложение BUTNCTL
Приложение BUTNCTL создает в своем главном окне пять кнопок (рис. 2.2).
Рис. 2.2. Главное окно приложения BUTNCTL
Кнопка «Button 1» работает также, как и в предыдущем приложении. А именно, если на нее нажать, появится диалоговая панель с сообщением о том, что нажата первая кнопка.
Остальные кнопки управляют первой кнопкой. С помощью кнопки «PUSH» вы можете нажимать первую кнопку (и она останется в нажатом состоянии), с помощью кнопки «POP» вы сможете вернуть первую кнопку в исходное состояние. Кнопка «OFF» блокирует первую кнопку, не пропуская в ее функцию окна сообщения от клавиатуры и мыши, кнопка «ON» разблокирует первую кнопку.
Когда вы будете проверять работу приложения, обратите внимание, что с помощью кнопок «PUSH» и «POP» вы сможете изменять состояние первой кнопки, даже если она заблокирована. Это связано с тем, что заблокированное окно не получает сообщения от мыши и клавиатуры, но получает другие сообщения, например, от таймера, других окон или приложений.
Главный файл приложения BUTNCTL приведен в листинге 2.3.
Листинг 2.3. Файл butnctl\butnctl.cpp
В приложении определены идентификаторы пяти кнопок — от IDB_Button1 до IDB_Button5, а также пять переменных для хранения идентификаторов окон класса ‘button».
Кнопки создаются точно также, как и в предыдущем приложении. Для каждой кнопки определяется свой идентификатор, с помощью которого функция окна сможет распознать источник сообщения WM_CONTROL.
Далее приложение изменяет параметры для всех пяти кнопок. Конечно, мы могли бы сразу создать кнопки с нужными параметрами, однако задачей нашего приложения является демонстрация средств управления параметрами кнопок и самими кнопками.
Длина первой кнопки увеличивается до 180 пикселов, для чего вызывается функция MoveWindow:
Для всех остальных кнопок изменяются надписи:
Функция окна обрабатывает сообщение WM_COMMAND, которое может поступать от всех пяти кнопок. Кнопки различаются по параметру wParam.
Если вы нажимаете первую кнопку, на экран выводится диалоговая панель с сообщением.
Если нажать на вторую кнопку (с надписью «DOWN»), функция окна передает сообщение первой кнопке, в результате чего она переходит в нажатое состояние:
Если нажать на кнопку с надписью «POP», возвращается исходное состояние первой кнопки:
Кнопка с надписью «OFF» предназначена для перевода первой кнопки в неактивное состояние. Для этого вызывается функция EnableWindow со значением второго параметра, равным FALSE:
И, наконец, последняя, пятая кнопка с надписью «ON» снова возвращает первую кнопку в активное состояние:
Файл определения модуля для приложения BUTNCTL приведен в листинге 2.4.
Листинг 2.4. Файл butnctl\butnctl.def
Переключатели
Очень часто в приложениях Windows требуется организовать выбор различных режимов работы. На рис. 2.3. показана диалоговая панель «Options», которая используется в текстовом процессоре Microsoft Word for Windows для настройки параметров клавиатуры.
Рис. 2.3. Диалоговая панель для настройки параметров клавиатуры в текстовом процессоре Microsoft Word for Windows
В этой диалоговой панели есть множество различных управляющих органов. В правом нижнем углу расположен орган управления (группа) в виде прямоугольника с заголовком «Context». Это окно класса «button», имеющее стиль BS_GROUPBOX. Внутри него расположены два переключателя. Они созданы также на базе класса «button», но имеют стиль BS_RADIOBUTTON (или BS_AUTORADIOBUTTON).
Группа с названием «Short Key» содержит два переключателя, созданных на базе окна «button», но имеющих стиль BS_CHECKBOX (или BS_AUTOCHECKBOX).
Переключатели BS_RADIOBUTTON и BS_AUTORADIOBUTTON используются аналогично кнопкам переключения диапазонов в радиоприемнике (отсюда и название стиля таких переключателей). Обычно в одной группе располагают несколько таких «радиопереключателей», причем включенным может быть только один (ни один радиоприемник не позволит вам принимать передачи сразу в двух диапазонах). Такие переключатели называются переключателями с зависимой фиксацией, так как включение одного переключателя в группе вызывает выключение остальных. Разумеется, ваше приложение должно само обеспечить такой режим работы переключателей.
Переключатели BS_CHECKBOX, BS_AUTOCHECKBOX, BS_3STATE, BS_AUTO3STATE используются как отдельные независимые переключатели. Из них можно сделать переключатель с независимой фиксацией, в котором одновременно могут быть включены несколько переключателей.
Разумеется, все сказанное выше относительно использования переключателей имеет скорее характер рекомендаций, чем обязательное требование. Однако при разработке приложения вам необходимо позаботиться о том, чтобы интерфейс пользователя соответствовал стандарту, изложенному в руководстве по разработке пользовательского интерфейса (это руководство поставляется в составе SDK и называется The Windows Interface: An Application Design Guide). В этом случае органы управления вашего приложения будут делать то, что ожидает от них пользователь, освоивший работу с другими приложениями Windows.
Обычно переключатели и группы переключателей используются в более сложных органах управления — в диалоговых панелях, которыми мы займемся позже. Однако ваше приложение может создавать отдельные переключатели в любом своем окне, как и рассмотренные нами ранее кнопки со стилями BS_PUSHBUTTON или BS_DEFPUSHBUTTON.
Вы можете работать с переключателями типа BS_AUTORADIOBUTTON или BS_AUTOCHECKBOX точно таким же образом, что и с кнопками типа BS_PUSHBUTTON или BS_DEFPUSHBUTTON. Когда вы устанавливаете курсор мыши на такой переключатель и нажимаете левую клавишу мыши, состояние переключателя меняется на противоположное. При этом неперечеркнутый квадратик становится перечеркнутым и наоборот, перечеркнутый квадратик становится неперечеркнутым. Состояние переключателя BS_AUTORADIOBUTTON отмечается жирной точкой, которая для включенного переключателя изображается внутри кружочка.
При изменении состояния переключателя родительское окно получает сообщение WM_COMMAND с кодом извещения BN_CLICKED.
Переключатель, имеющий стиль BS_3STATE или BS_AUTO3STATE, внешне похож на переключатель со стилем BS_CHECKBOX, но дополнительно имеет третье состояние. В этом третьем состоянии он изображается серым цветом и может использоваться, например, для индикации недоступного для установки параметра.
Слово «AUTO» в названии стиля переключателя используется для обозначения режима автоматической перерисовки переключателя при изменении его состояния. О чем здесь идет речь?
Когда вы нажимаете кнопку, имеющую стиль BS_PUSHBUTTON или BS_DEFPUSHBUTTON, она автоматически уходит «вглубь», т. е. автоматически перерисовывается в соответствии со своим текущим состоянием. Переключатели BS_CHECKBOX, BS_RADIOBUTTON, а также BS_3STATE не перерисовываются при их переключении. Вы должны их перерисовывать сами, посылая им сообщение BM_SETCHECK:
Параметр wParam сообщения BM_SETCHECK определяет состояние переключателя, которое необходимо установить:
Значение | Описание |
0 | Установка переключателя в выключенное состояние (прямоугольник не перечеркнут, в кружке нет точки) |
1 | Установка переключателя во включенное состояние (прямоугольник перечеркнут, в кружке имеется точка) |
2 | Установка переключателя в неактивное состояние. Это значение используется только для переключателей, имеющих стиль BS_3STATE или BS_AUTO3STATE. При этом переключатель будет изображен серым цветом |
Параметр lParam сообщения BM_SETCHECK должен быть равен 0.
В любой момент времени приложение может узнать состояние переключателя, посылая ему сообщение BM_GETCHECK:
Парамеры wParam и lParam сообщения BM_GETCHECK должны быть равны 0.
Возвращаемое значение, которое будет записано в переменную nState, может быть равно 0 (для выключенного переключателя), 1 (для включенного) или 2 (для переключателя, который находится в неактивном состоянии и отображается серым цветом).
Мы еще вернемся к переключателям, когда будем заниматься диалоговыми панелями.
Кнопки, которые рисует родительское окно
Если вас не удовлетворяет внешний вид стандартных кнопок (или других стандартных органов управления, созданных на базе класса «button»), вы можете при создании кнопки указать стиль BS_OWNERDRAW. Этот стиль несовместим с остальными стилями кнопок.
Если вы создали кнопку со стилем BS_OWNERDRAW, она будет работать аналогично кнопкам других стилей, но процедура рисования кнопки возлагается на родительское окно. При этом оно может нарисовать кнопку с использованием пиктограмм (с помощью функции DrawIcon), графических изображений bitmap или любым другим способом.
Обычно кнопки BS_OWNERDRAW используют при отображении наборов инструментальных средств, называемых Toolbar. Примером такого набора может служить набор кнопок с пиктограммами, предназначенных для запуска команд в текстовом процессоре Microsoft Word for Windows (рис. 2.4).
Рис. 2.4. Кнопки с пиктограммами
Кнопка BS_OWNERDRAW, как и кнопка BS_PUSHBUTTON, посылает в родительское окно сообщение WM_COMMAND с кодом извещения BN_CLICKED. Дополнительно такая кнопка посылает в родительское окно сообщение WM_DRAWITEM, которое говорит о том, что надо нарисовать орган управления в том или ином состоянии.
Обработчик сообщения WM_DRAWITEM должен вернуть значение TRUE.
Параметр wParam сообщения WM_DRAWITEM содержит идентификатор органа управления, пославшего сообщение WM_DRAWITEM (для органа управления типа меню этот параметр равен 0).
Параметр lParam содержит дальний указатель на структуру типа DRAWITEMSTRUCT, описанную в файле windows.h:
В файле windows.h определены также ближний и дальний указатели на эту структуру:
Анализируя поля структуры DRAWITEMSTRUCT, родительское окно может определить тип и идентификатор органа управления, требующего перерисовки, а также состояние, в котором необходимо изобразить данный орган управления (включен, выключен, получил фокус ввода, неактивен, выбран для использования).
Приведем назначение отдельных полей структуры DRAWITEMSTRUCT.
Имя поля | Описание |
CtlType | Тип органа управления. Может принимать следующие значения: ODT_BUTTONODT_BUTTON — кнопка; ODT_COMBOBOXODT_COMBOBOX — орган COMBOBOX (рассмотрим позже); ODT_LISTBOXODT_LISTBOX — орган LISTBOX (рассмотрим позже); ODT_MENUODT_MENU — меню |
CtlID | Идентификатор органа управления. Не используется для меню |
itemID | Идентификатор строки для органов COMBOBOX, LISTBOX или меню |
itemAction | Действия, которые необходимо выполнить при изображении органа управления. Определен в виде отдельных битовых флагов: ODA_DRAWENTIREODA_DRAWENTIRE — требуется перерисовать весь орган управления; ODA_FOCUSODA_FOCUS — этот бит устанавливается в 1, если орган управления получил или потерял фокус ввода, новое состояние органа управления можно узнать, проанализировав содержимое поля itemState; ODA_SELECTODA_SELECT — изменилось состояние органа управления (он стал включенным, выключенным или неактивным), для уточнения состояния необходимо использовать поле itemState |
itemState | Вид, в котором необходимо изобразить орган управления. Определен в виде отдельных битовых флагов: ODS_CHECKEDODS_CHECKED — выбрана строка меню (этот бит используется только для меню); ODS_DISABLEDODS_DISABLED — орган управления неактивен; ODS_FOCUSODS_FOCUS — орган управления получил фокус ввода; ODS_GRAYEDODS_GRAYED — строка меню должна быть изображена серым цветом (этот бит используется только для меню); ODS_SELECTEDODS_SELECTED — орган управления выбран |
hwndItem | Для кнопок, органов управления COMBOBOX и LISTBOX это поле содержит идентификатор окна. Для меню это поле содержит идентификатор меню |
hDC | Контекст устройства, который необходимо использовать для рисования органа управления |
rcItem | Прямоугольные границы органа управления, внутри которого его необходимо нарисовать |
itemData | Используется только для органов управления COMBOBOX и LISTBOX |
Приложение OWNBUT
Приложение OWNBUT создает кнопку со стилем BS_OWNERDRAW. Функция главного окна приложения рисует кнопку при помощи трех изображений bitmap, загружая их при необходимости из ресурсов. Первое изображение предназначено для рисования отжатой кнопки, второе — нажатой, и третье — неактивной.
Внешний вид главного окна приложения показан на рис. 2.5.
Рис. 2.5. Главное окно приложения OWNBUT
В верхнем левом углу главного окна расположена кнопка со стилем BS_OWNERDRAW. Остальные кнопки предназначены для управления первой кнопкой и работают так же, как и предыдущем приложении.
Главный файл приложения OWNBTN представлен в листинге 2.5.
Листинг 2.5. Файл ownbut\ownbut.cpp
В начале своей работы функция WinMain сохраняет идентификатор текущей копии приложения в глобальной переменной:
Затем она инициализирует главное окно приложения и создает пять кнопок, первая из которых имеет стиль BS_OWNERDRAW:
Функция главного окна приложения OWNBTN кроме сообщения WM_COMMAND дополнительно обрабатывает сообщение WM_DRAWITEM, в ответ на которое она вызывает функцию DrawButton, определенную в нашем приложении:
Функция DrawButton перерисовывает кнопку. В качестве параметра этой функции передается указатель на структуру DRAWITEMSTRUCT, содержащую всю информацию, необходимую для перерисовки кнопки.
Вначале эта функция проверяет тип органа управления, приславшего сообщение WM_DRAWITEM. Тип должен быть равен ODT_BUTTON.
Затем проверяется идентификатор кнопки. В нашем приложении есть только одна кнопка со стилем BS_OWNERDRAW, но их могло бы быть и несколько. В переменную ResourceID загружается идентификатор ресурса (изображения bitmap), соответствующего изображению кнопки в нормальном (отжатом) состоянии:
Далее в зависимости от текущего состояния кнопки на момент прихода сообщения WM_DRAWITEM содержимое переменной ResourceID заменяется на идентификатор соответствующего изображения кнопки.
Для выбранной кнопки (в поле itemState структуры DRAWITEMSTRUCT установлен бит ODS_SELECTED) в переменную ResourceID записывается идентификатор изображения нажатой кнопки IDR_BUTTONDOWN.
Для неактивной кнопки в эту же переменную записывается идентификатор изображения неактивной кнопки IDR_BUTTONGR.
После этого нужное изображение загружается из ресурсов приложения, для чего вызывается функция LoadBitmap:
Далее функция DrawButton проверяет действие, которое нужно выполнить при рисовании кнопки. Если состояние кнопки изменилось (установлен бит ODA_SELECT) и требуется перерисовать всю кнопку (установлен бит ODA_DRAWENTIRE), выполняется вызов функции DrawBitmap, определенной в нашем приложении.
Создавая функцию DrawBitmap, мы сделали так, что количество, назначение и формат ее параметров в точности соответствует функции DrawIcon, с помощью которой мы рисовали пиктограммы (вы можете легко изменить исходный текст приложения OWNBUT для того чтобы для рисования кнопки использовать не изображения bitmap, а пиктограммы; сделайте это самостоятельно). В нашем примере в качестве первого параметра функции передается контекст устройства, полученный в структуре DRAWITEMSTRUCT вместе с сообщением WM_DRAWITEM. Второй и третий параметры используются для определения координат верхнего левого угла кнопки в системе координат, связанной с родительским окном. Последний параметр — идентификатор изображения bitmap, который необходимо нарисовать:
После того как кнопка нарисована, следует удалить bitmap, загруженный функцией LoadBitmap. Для этого наше приложение вызывает функцию DeleteObject:
Идентификаторы кнопок и изображений bitmap определены в файле ownbut.hpp (листинг 2.6).
Листинг 2.6. Файл ownbut\ownbut.hpp
В файле описания ресурсов приложения (листинг 2.7) определены три изображения bitmap, используемые для рисования кнопки в различных состояниях.
Листинг 2.7. Файл ownbut\ownbut.rc
В листинге 2.8 изображен файл mybtnup.bmp. Этот файл содержит объемное изображение кнопки в нормальном (отжатом) состоянии.
Листинг 2.8. Файл ownbut\mybtnup.bmp
Файл mybtndn.bmp (листинг 2.9) хранит изображение кнопки в нажатом состоянии.
Листинг 2.9. Файл ownbut\mybtndn.bmp
Для изображения кнопки в неактивном состоянии используется файл mybtngr.bmp (листинг 2.10).
Листинг 2.10. Файл ownbut\mybtngr.bmp
Для рисования изображения bitmap мы подготовили функцию DrawBitmap (листинг 2.11). Детальное описание этой функции мы отложим до главы, посвященной изображениям bitmap.
Листинг 2.11. Файл ownbut\drawbmp.cpp
Файл определения модуля для приложения OWNBUT представлен в листинге 2.12.
Листинг 2.12. Файл ownbut\ownbut.def
Кнопки и клавиатура
Обычно для работы с кнопками используется мышь. Но, как мы уже говорили, с приложениями Windows вы можете работать и без мыши. В частности, в диалоговых панелях вы можете, нажимая клавишу , передавать фокус ввода от одной кнопки к другой. Если кнопка имеет фокус ввода, ее функция окна будет получать сообщения от клавиатуры. Кнопка реагирует только на клавишу пробела — если вы нажмете пробел, когда кнопка имеет фокус ввода, кнопка (или переключатель, который есть ни что иное, как разновидность кнопки) изменит свое состояние.
Для того чтобы ваше приложение могло использовать клавишу для передачи фокуса ввода от одного органа управления другому, оно должно создать для клавиши свой обработчик сообщения WM_CHAR. Этот обработчик должен установить фокус ввода на следующий (из имеющихся) орган управления, вызвав функцию SetFocus.
К счастью, в Windows имеется объект, специально предназначенный для объединения нескольких органов управления — диалоговая панель. Функции поддержки диалоговых панелей определены внутри Windows. Они выполняют всю работу, необходимую для организации передачи фокуса ввода между различными органами управления, расположенными на диалоговой панели.