Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
GOS / Дисциплины специализации.doc
Скачиваний:
42
Добавлен:
09.05.2015
Размер:
1.61 Mб
Скачать

9. Модальные и не модальные панели диалога.

Модальные и немодальные окна диалога

Окно диалога это специальный вид окна, предназначенный обычно для взаимодействия пользователя с элементами управления, расположенными внутри диалогов. Окна диалогов бывают модальными (modal) и немодальными (modeless). (modal). Модальные диалоговые окна не дают пользователю возможность перенести фокус ввода на другое окно в том же программном потоке. То есть при открытом модальном диалоге сообщения не поступают в цикл обработки сообщений главного окна. В случае немодального диалога, сообщения поступают в цикл обработки сообщений главного окна приложения и должны быть перенаправлены в окно диалога.

Диалоговые окна обычно строятся на основе специального типа ресурсов – шаблона окна диалога, который создается с помощью визуальных средств пакета Visual Studio. Для создания модального диалогового окна нужно вызвать функцию API - Dialog Box и передать ей в качестве параметров: ресурс диалога, на основе которого будет строиться диалоговое окно; ссылку на окно родителя или NULL, если окно не имеет родителя и является главным окном приложения; адрес оконной процедуры диалога. Оконная процедура диалога обрабатывает сообщения, поступающие в окно диалога. Эта функция возвращает управление только после закрытия окна диалога. Обработка сообщений диалоговыми окнами имеет свои особенности, сообщение WM_PAINT и WM_DESTROY – диалогом не обрабатываются. Вместо сообщения WM_CREATE для инициализации диалога, посылается специальное сообщение WM_INITDIALOG. Как правило, диалоговое окно обрабатывает только сообщение WM_COMMAND, которое посылается большинством элементов управления, расположенных в диалоге. Взаимодействие с элементами управления осуществляется с помощью сообщений, которые могут быть посланы с помощью функции SendMessage с нужным набором параметров. Первым параметром функции SendMessage обычно служит указатель на элемент управления, полученный с помощью вызова функции GetDlgItem.

В отличие от модальных диалоговых окон, немодальные создаются с помощью функции CreateDialog. Закрыть немодальное диалоговое окно можно с помощью функции DestroyWindow, желательно при этом обнулить также дескриптор окна диалога. При создании ресурса немодального окна диалога нужно указывать стиль шаблона диалога WS_VISEBLE, иначе диалоговое окно не будет видимым, и нужно будет вызывать функцию ShowWindow, чтобы его показать.

Модальные диалоговые панели

Модальные панели блокируют выполнение основного потока приложения до своего завершения, в отличие от немодальных, которые мы рассмотрим позже. Перед созданием модальной панели программист должен написать т.н. функцию диалога — это аналог функции окна приложения, но в нее будут поступать сообщения от диалоговой панели. Прототип функции диалога:

INT_PTR CALLBACK DialogProc(

HWND hwndDlg, //HWND диалоговой панели

UINT uMsg, //поступившее сообщение

WPARAM wParam,

LPARAM lParam

);

Смысл параметров аналогичен функции окна приложения. Сообщения обрабатываются так же, как и в обычной функции окна. Единственное отличие — функция диалога не должна передавать необработанные сообщения функции DefWindowProc(), т.к. необработанные сообщения обрабатывается самой функцией окна диалоговой панели (в действительности функция диалога не является функцией окна, она вызывается функцией окна диалоговой панели). Функция диалога не обрабатывает сообщения WM_CREATE, WM_PAINT, WM_DESTROY (точнее, внутренняя функция окна диалоговой панели не выпускает их наружу, в функцию диалога). Вместо WM_CREATE функция диалога может обрабатывать сообщение WM_INITDIALOG, которое поступает, когда окно уже создано, но еще не появилось на экране; тем самым программисту дается возможность проинициализировать внешний вид диалога. Чаще всего функция диалога обрабатывает сообщение WM_COMMAND, поступающее от элементов управления.

Если в wParam вместе с сообщением WM_COMMAND поступает константа IDOK, это значит, что пользователь нажал клавишу Enter, когда ни один из элементов управления не имел фокуса ввода. Во многих случаях программисты создают на диалоговых панелях имеют кнопку с надписью Ok, которая подразумевает сохранение изменений, сделанных пользователем в диалоге, и окончание работы с диалогом. Стандартная функция окна диалоговой панели закрывает окно в случае этого сообщения. Также в функцию диалога вместе с WM_COMMAND в wParam может поступить IDCANCEL. Обычно это сигнализирует о том, что пользователь закрывает окно диалога и отклоняет всякие сделанные им изменения. Также оно поступает, когда пользователь нажимает клавишу Esc, либо закрывает окно с помощью системного меню.

Стоит еще заметить, что если вы создаете на диалоговой панели кнопки с идентификаторами IDOK или IDCANCEL (параметр hMenu в CreateWindow()), они будут действовать так же.

Создать шаблон диалоговой панели в Visual C++ или внешнем редакторе ресурсов очень легко. У вас под рукой находится панель, на которой находятся кнопки с изображениями базовых диалоговых классов Windows. Перетянув изображение на диалоговую панель, вы тем самым создадите соответствующий класс на диалоговой панели. Вы можете открыть .rc-файл, чтобы увидеть, как пишет скрипт диалога среда Visual C++. В окне Properties можно назначить любой стиль для класса внутри диалога, точно так же, как вы это делали вручную, редактируя .rc-файл.

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

Наиболее часто используется функция:

INT_PTR DialogBox(

HINSTANCE hInstance,

LPCTSTR lpTemplate,

HWND hWndParent,

DLGPROC lpDialogFunc

);

hInstance — это HINSTANCE того модуля, в котором находится ресурс с шаблоном диалога (пока что мы используем только один исполняемый модуль, поэтому этот параметр будет равен hInstance из WinMain()). LpTemplate — это строка, идентифицирующая ресурс диалоговой панели. Если идентификатор ресурса задан в виде числовой константы (например IDD_DIALOG1), то следует преобразовать ее с помощью макроса MAKEINTRESOURCE, который был рассмотрен раньше. hWndParent — HWND родительского окна. LpDialogFunc — указатель на функцию диалога.

Функция DialogBox() не возвращает управление до тех пор, пока окно диалоговой панели не будет уничтожено. Для закрытия диалоговой панели функция диалога должна вызвать функцию:

BOOL EndDialog(

HWND hDlg, //HWND диалоговой панели

INT_PTR nResult //серьезность ошибки

);

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

Немодальные диалоговые панели

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

Немодальные (modeless) диалоговые панели должны иметь стиль pop-up, заголовок и рамку, т.е. при создании немодальной панели вы должны указать как минимум стили WS_POPUP, WS_CAPTION, WS_BORDER и WS_SYSMENU. Стоит заметить, что система не показывает автоматически окно на экране после создания, если не указан стиль WS_VISIBLE.

Немодальные панели удобно использовать для организации панелей инструментов и тому подобных диалогов.

Ваше приложение может создать немодальную диалоговую панель, используя функции:

HWND CreateDialog(

HINSTANCE hInstance, //HINSTANCE модуля с ресурсом диалога

LPCTSTR lpTemplate, //имя ресурса диалога

HWND hWndParent, //идентификатор окна-родителя

DLGPROC lpDialogFunc //функция диалога

);

и

HWND CreateDialogIndirect(

HINSTANCE hInstance, //HINSTANCE модуля с ресурсом диалога

LPCDLGTEMPLATE lpTemplate, //имя ресурса диалога

HWND hWndParent, //идентификатор окна-родителя

DLGPROC lpDialogFunc //функция диалога

);

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

Функции CreateDialog() и другие три возващают HWND на созданное диалоговое окно, который приложение должно сохранить, чтобы потом иметь возможность управлять созданным окном. Заметьте, что CreateDialog() возвращает управление сразу же после создания диалога, и программа продолжает работать дальше, в отличие от DialogBox() для модальных окон.

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

BOOL IsDialogMessage(

HWND hDlg, //идентификатор немодальной диалоговой панели

LPMSG lpMsg //сообщение для проверки

);

Если задать в параметрах этой функции HWND диалоговой панели и поступившее сообщение, можно проверить, пришло ли это сообщение от этой диалоговой панели. Функция возвращает TRUE, если сообщение пришло от окна HWND, или FALSE в противном случае. Включив эту функцию в главный цикл обработки сообщений, можно отсеять сообщения определенной диалоговой панели (в нашем случае hWndDlg):

While(GetMessage(&msg, 0, 0, 0))

{

if(!IsDialogMessage(hWndDlg, &msg))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}