Московский инженерно-физический институт

Вид материалаПрактикум

Содержание


Обслуживание модального диалога
BOOL CALLBACK DlgProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
Lresult –
Подобный материал:
1   ...   12   13   14   15   16   17   18   19   ...   24

Обслуживание модального диалога


Открытие модального диалога осуществляется в нашем примере (да и практически всегда) при выборе соответствующей команды меню (у нас – команды "Открыть..." с идентификатором MI­ABOUT). Как уже отмечалось ранее, выбор любого пункта меню заставляет Windows послать в приложение сообщение WMCOM­MAND, что приводит к передаче управления на прикладную фун­кцию OnCommand(). Через второй параметр этой функции передается значение идентификатора выбранного пункта меню. Анализ идентификатора с помощью конструкции switch-case позволяет выполнить в ответ на выбор каждого пункта меню тре­буемые действия. Открытие модального диалога осуществляется вызовом функции Windows DialogBox().

Как можно увидеть из примера 4-1, функция DialogBox() использует четыре параметра. Первый из них – дескриптор приложения. Этот дескриптор не передается автоматически в оконную функцию и далее в функции обработки сообщений. Имея в виду, что он понадобится нам для вызова функции DialogBox(), мы сохранили его в глобальной переменной hIn еще в процессе регистрации главного окна приложения.

Вторым аргументом функции DialogBox() служит указатель на имя диалога, использованное в сценарии этого диалога в файле ресурсов (или само это имя). У нас это строка "About".

Третий аргумент – дескриптор окна, в котором открывается диалог. Этот дескриптор нужен многим функциям Windows, поэтому он передается в оконную функцию при ее вызове, и нет необходимости запоминать его в глобальной переменной (хотя иногда, если окон много, это все же приходится делать).

Четвертый аргумент принципиально является важнейшим; он представляет собой имя оконной функции для окна диалога. Как уже отмечалось, каждое окно, входящее в состав приложения, обязано иметь свою оконную функцию. Оконная функция диалога вызывается системой Windows в процессе инициализации диалога, а также при выполнении пользователем каких-либо операций с элементами управления диалогового окна. Параметры этой функции такие же, как у оконной функции главного окна, однако возвращаемое значение должно иметь тип не LRESULT, а BOOL. Роль функции создания диалога DialogBox() заключается прежде всего в том, что она привязывает к окну диалога соответствующую ему оконную функцию, состоящую из фрагментов обслуживания элементов управления диалогового окна.

Назначение оконной функции диалогового окна, как и любой другой оконной функции, состоит в обработке сообщений, поступающих в это окно. Сообщения могут поступать из системы Windows по инициативе системы (например, сообщение о создании диалога), а могут быть следствием манипуляций элементами управления в диалоговом окне, например нажатия пользователем той или иной кнопки.

Для большей части сообщений, поступающих в диалоговое окно, в файле WINDOWSX.H можно найти макросы вида HANDLE­WMсообщение, поэтому структура оконной функции диалога может быть в точности такой же, как и для оконной функции главного окна:

BOOL CALLBACK DlgProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){

switch(msg){

HANDLE_MSG(hwnd,WM_INITDIALOG,DlgOnInitDialog);

HANDLE_MSG(hwnd,WM_COMMAND,DlgOnCommand);

default:

return FALSE;//Возврат FALSE для остальных сообщений

}

}

На первый взгляд такое решение представляется не вполне корректным. Действительно, оконная функция обычного (не диалогового) окна в соответствии с ее прототипом должна возвращать значение типа LRESULT, и макросы HANDLEWMсообщение должны приводить к возврату именно такого значения, в то время как макросы, используемые в оконной функции диалога, должны возвращать, в соответствии с ее прототипом, значение типа BOOL. Однако в 32-разрядных приложениях оба эти типа: и BOOL, и LRESULT – представляют собой попросту целые числа (как, между прочим, и HWND, WPARAM, LPARAM, HPEN и др.), и их можно свободно преобразовывать друг в друга по правилам явного преобразования языка С++. В макроопределениях макросов HANDLEWM­сообщение, выполняются в необходимых случаях такие преобразования (часто сразу в несколько типов, например, LRESULT, DWORD, UINT и даже HBRUSH), что дает возможность использовать эти макросы как в обычных, так и в диалоговых оконных функциях.

Рассмотрим отличия диалоговой функции. Для диалогов нет необходимости, более того, недопустимо вызывать функцию обработки сообщений по умолчанию DefWindowProc(). Эта функция вызывается только для окон (главного и порожденных), которые строит и обслуживает пользователь. Диалог же организует и поддерживает Windows, которая и так знает, что ей надлежит делать с большинством сообщений, поступающих в диалоговое окно.

Надо заметить, что в процессе создания диалога и работы с ним Windows посылает в него большое количество сообщений, на которые сама же и отвечает. Программа же обрабатывает лишь немногие из них. Прежде всего, это сообщение WMINITDIALOG о создании диалога и WMCOMMAND о работе пользователя с элементами управления; во многих случаях приходится обрабатывать и другие сообщения.

Windows должна знать, какие сообщения мы обрабатываем, а какие нет. Обычно руководствуются следующим правилом: если оконная функция диалога обрабатывает сообщение, она возвращает значение TRUE, а если не обрабатывает – FALSE. Поэтому для всех сообщений, не обрабатываемых в приложении, надо просто завершить оконную функцию, вернув значение FALSE (см. предложение с default в приведенном выше фрагменте).

В рассматриваемом примере обрабатываются лишь два сообщения модального диалога. Сообщение WMINITDIALOG поступает в диалоговое окно непосредственно перед его выводом на экран и предназначено для выполнения инициализирующих действий, если они предусмотрены. В нашей программе их нет, однако перехват сообщения WMINITDIALOG все же имеет смысл. Дело в том, что возврат в Windows в ответ на это сообщение значения TRUE приводит к специфическим действиям – установке так называемого фокуса ввода на определенный элемент управления диалогом. Обычно это элемент, описанный первым в файле ресурсов. Если элемент управления владеет фокусом ввода, то в него поступают все сообщения от клавиатуры. Если фокус ввода установлен, например, на поле для ввода текста, то вводимый с клавиатуры текст будет попадать именно в это поле; если фокус ввода установлен на кнопке, нажатие клавиши Enter приведет к “нажатию” этой кнопки. В нашем диалоге предусмотрена единственная кнопка "Закрыть", и помещение на нее фокуса ввода позволяет управлять этой кнопкой не только мышью, но и клавишей Enter. Между прочим, имея в виду такую возможность, мы поместили предложение описания кнопки первым в перечне элементов управления (которых у нас всего два).

Второе обрабатываемое в программе сообщение, WMCOMMAND, поступает в диалоговое окно в следующих случаях:
  • нажата кнопка "Закрыть"; передаваемый в функцию обработки сообщения WMCOMMAND идентификатор элемента управления id равен в нашем случае ID_OK (id=100), поскольку именно эта константа закреплена за кнопкой в файле ресурсов;
  • с клавиатуры введена команда Alt+F4 (id=IDCANCEL=2);
  • пользователь щелкнул по кнопке в правом верхнем углу диалогового окна (id=IDCANCEL).

В нашем простом диалоге любое из этих действий должно приводить к закрытию диалогового окна, что и выполняется в функции DlgOnCommand() путем вызова функции EndDialog().

Функция EndDialog() вызывает два действия: гасится диалоговое окно и завершается выполнение функции DialogBox(). Вспомним, что для вывода на экран модального диалога надо вызывать функцию DialogBox(). Вспомним также, что пока на экране присутствует окно модального диалога, все остальные окна приложения блокированы: пользователь может работать только с элементами управления модального диалога. Именно этим модальный диалог и отличается от немодального, который не препятствует манипуляциям с любыми другими окнами и элементами управления приложения.

Все время, пока пользователь работает с модальным диалогом, выполняется функция DialogBox(). Другими словами, выполнение программы как бы остановилось в точке вызова DialogBox() в функции OnCommand(), которая является фрагментом оконной функции главного окна. Эта остановка не мешает Windows вызывать по мере необходимости оконную функцию диалога и вложенные в нее подпрограммы; однако пока программа не завершила обработку сообщения WM_COMMAND главного окна, она не может перейти к обработке следующих сообщений, поступающих в главное окно.

Вызов функции EndDialog() завершает выполнение функций DialogBox() и (в нашем случае) OnCommand(), снова активизируя главное окно приложения.

Функция EndDialog() требует двух параметров типов HWND и int соответственно. Первый – это, естественно, дескриптор диалогового окна, передаваемый из Windows в оконную функцию диалога DlgProc() при ее вызове, а из нее в функцию DlgOnCommand(). Второй параметр представляет собой целое число, которое будет служить возвращаемым значением для функции создания диалогового окна DialogBox(). Для того, чтобы использовать это значение, открывать диалог следовало так:

int result=DialogBox(...);

Тогда второй фактический аргумент функции EndDialog() вернулся бы в переменную result. Таким образом создается возможность обрабатывать коды завершения диалогового окна.