- •Лабораторный практикум «Основы разработки приложений Windows» Книга 1
- •Часть 1. Теоретические сведения4
- •Часть 2. Лабораторный практикум95
- •Часть 1 Теоретические сведения
- •1. Структура приложения Windows Простейшая программа с главным окном
- •Структура программы
- •Главная функция WinMain()
- •Регистрация класса окна
- •Создание и показ окна
- •Сообщения Windows и цикл их обработки
- •Оконная функция
- •Макрос handle_msg и структурирование программы
- •2. Интерфейс графических устройств
- •Простая программа, использующая средства gdi
- •Обработка сообщений wmpaint
- •Контекст устройства
- •Использование графических инструментов
- •3. Ресурсы: меню Простая программа с меню
- •Файл ресурсов
- •Описание меню в файле ресурсов
- •Сообщение wmcommand
- •Программное создание меню
- •Плавающее меню
- •Инструментальная панель
- •Всплывающие подсказки
- •0,"Первая строка"
- •1,"Вторая строка"
- •2,"Третья строка"
- •4. Ресурсы: диалоговые окна
- •Простая программа с меню и диалогом
- •Описание диалога в файле ресурсов
- •Обслуживание модального диалога
- •Модальный диалог как главное окно приложения
- •Немодальный диалог
- •Список в диалоговом окне
- •Окно редактирования и статический элемент управления
- •Графика в диалоговом окне
- •Перекрашивание диалогового окна и его элементов
- •Часть 2 Лабораторный практикум Работы лабораторного практикума Работа 1. Вызов функций Windows
- •Работа 2. Главное окно приложения (пример 1-1 из настоящего пособия)
- •Работа 3. Вывод в главное окно приложения текста и фигур (пример 2-1 из настоящего пособия)
- •Работа 4.Вывод в главное окно приложения текста и фигур (индивидуальное задание а)
- •Работа 5. Меню и модальный диалог (пример 4-1 из настоящего пособия)
- •Работа 6.Меню (индивидуальное задание в)
- •Работа 7.Модальный диалог в качестве главного окна приложения (индивидуальное задание с)
- •Работа 8.Вывод графика в главное окно приложения (индивидуальное заданиеD)
- •Работа 9. Немодальный диалог
- •Работа 10. Диалог с окном редактирования
- •Работа 11. Программное создание меню
- •Работа 12. Плавающее меню
- •Работа 13. График в диалоговом окне
- •Работа 14. Инструментальная панель (tool bar)
- •Работа 15. Инструментальная панель со всплывающими подсказками (tool tips)
- •Работа 16. Пользовательские пиктограммы и курсоры
- •Работа 17. Локализация программных продуктов
- •Индивидуальные задания лабораторного практикума
Обслуживание модального диалога
Открытие модального диалога осуществляется в нашем примере (да и практически всегда) при выборе соответствующей команды меню (у нас – команды "Открыть..."с идентификаторомMIABOUT). Как уже отмечалось ранее, выбор любого пункта меню заставляет Windows послать в приложение сообщениеWMCOMMAND, что приводит к передаче управления на прикладную функциюOnCommand().Через второй параметр этой функции передается значение идентификатора выбранного пункта меню. Анализ идентификатора с помощью конструкцииswitch-case позволяет выполнить в ответ на выбор каждого пункта меню требуемые действия. Открытие модального диалога осуществляется вызовом функции WindowsDialogBox().
Как можно увидеть из примера 4-1, функция DialogBox()использует четыре параметра. Первый из них – дескриптор приложения. Этот дескриптор не передается автоматически в оконную функцию и далее в функции обработки сообщений. Имея в виду, что он понадобится нам для вызова функцииDialogBox(), мы сохранили его в глобальной переменнойhInеще в процессе регистрации главного окна приложения.
Вторым аргументом функции DialogBox()служит указатель на имя диалога, использованное в сценарии этого диалога в файле ресурсов (или само это имя). У нас это строка"About".
Третий аргумент – дескриптор окна, в котором открывается диалог. Этот дескриптор нужен многим функциям Windows, поэтому он передается в оконную функцию при ее вызове, и нет необходимости запоминать его в глобальной переменной (хотя иногда, если окон много, это все же приходится делать).
Четвертый аргумент принципиально является важнейшим; он представляет собой имя оконной функции для окна диалога. Как уже отмечалось, каждое окно, входящее в состав приложения, обязано иметь свою оконную функцию. Оконная функция диалога вызывается системой Windows в процессе инициализации диалога, а также при выполнении пользователем каких-либо операций с элементами управления диалогового окна. Параметры этой функции такие же, как у оконной функции главного окна, однако возвращаемое значение должно иметь тип не LRESULT, аBOOL. Роль функции создания диалогаDialogBox() заключается прежде всего в том, что она привязывает к окну диалога соответствующую ему оконную функцию, состоящую из фрагментов обслуживания элементов управления диалогового окна.
Назначение оконной функции диалогового окна, как и любой другой оконной функции, состоит в обработке сообщений, поступающих в это окно. Сообщения могут поступать из системы Windows по инициативе системы (например, сообщение о создании диалога), а могут быть следствием манипуляций элементами управления в диалоговом окне, например нажатия пользователем той или иной кнопки.
Для большей части сообщений, поступающих в диалоговое окно, в файле WINDOWSX.Hможно найти макросы видаHANDLEWMсообщение, поэтому структура оконной функции диалога может быть в точности такой же, как и для оконной функции главного окна:
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, и макросыHANDLEWMсообщениедолжны приводить к возврату именно такого значения, в то время как макросы, используемые в оконной функции диалога, должны возвращать, в соответствии сеепрототипом, значение типаBOOL.Однако в 32-разрядных приложениях оба эти типа: иBOOL, и LRESULT –представляют собой попросту целые числа (как, между прочим, иHWND, WPARAM, LPARAM,HPEN и др.), и их можно свободно преобразовывать друг в друга по правилам явного преобразования языка С++. В макроопределениях макросовHANDLEWMсообщение, выполняются в необходимых случаях такие преобразования (часто сразу в несколько типов, например,LRESULT, DWORD, UINT и дажеHBRUSH), что дает возможность использовать эти макросы как в обычных, так и в диалоговых оконных функциях.
Рассмотрим отличия диалоговой функции. Для диалогов нет необходимости, более того, недопустимо вызывать функцию обработки сообщений по умолчанию DefWindowProc(). Эта функция вызывается только для окон (главного и порожденных), которые строит и обслуживает пользователь. Диалог же организует и поддерживает Windows, которая и так знает, что ей надлежит делать с большинством сообщений, поступающих в диалоговое окно.
Надо заметить, что в процессе создания диалога и работы с ним Windows посылает в него большое количество сообщений, на которые сама же и отвечает. Программа же обрабатывает лишь немногие из них. Прежде всего, это сообщение WMINITDIALOG о создании диалога и WMCOMMAND о работе пользователя с элементами управления; во многих случаях приходится обрабатывать и другие сообщения.
Windows должна знать, какие сообщения мы обрабатываем, а какие нет. Обычно руководствуются следующим правилом: если оконная функция диалога обрабатывает сообщение, она возвращает значение TRUE, а если не обрабатывает –FALSE. Поэтому для всех сообщений, не обрабатываемых в приложении, надо просто завершить оконную функцию, вернув значениеFALSE(см. предложение сdefaultв приведенном выше фрагменте).
В рассматриваемом примере обрабатываются лишь два сообщения модального диалога. Сообщение WMINITDIALOGпоступает в диалоговое окно непосредственно перед его выводом на экран и предназначено для выполнения инициализирующих действий, если они предусмотрены. В нашей программе их нет, однако перехват сообщенияWMINITDIALOGвсе же имеет смысл. Дело в том, что возврат в Windows в ответ на это сообщение значенияTRUEприводит к специфическим действиям – установке так называемого фокуса ввода на определенный элемент управления диалогом. Обычно это элемент, описанный первым в файле ресурсов. Если элемент управления владеет фокусом ввода, то в него поступают все сообщения от клавиатуры. Если фокус ввода установлен, например, на поле для ввода текста, то вводимый с клавиатуры текст будет попадать именно в это поле; если фокус ввода установлен на кнопке, нажатие клавиши Enter приведет к “нажатию” этой кнопки. В нашем диалоге предусмотрена единственная кнопка"Закрыть", и помещение на нее фокуса ввода позволяет управлять этой кнопкой не только мышью, но и клавишей Enter. Между прочим, имея в виду такую возможность, мы поместили предложение описания кнопкипервымв перечне элементов управления (которых у нас всего два).
Второе обрабатываемое в программе сообщение, WMCOMMAND, поступает в диалоговое окно в следующих случаях:
нажата кнопка "Закрыть"; передаваемый в функцию обработки сообщенияWMCOMMANDидентификатор элемента управления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. Таким образом создается возможность обрабатывать коды завершения диалогового окна.