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

5.9. Использование немодального диалога

Рис. 5.3. Пример работы Win-приложения с окном ввода

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

Для создания немодального диалога вместо функции DialogBox() используется функция API CreateDialog():

HWND CreateDialog(HINSTANCE hThisInst,

LPCSTR lpName,

HWND hwnd,

DLGPROC IpDFunc);

Здесь hThisInst – дескриптор текущего экземпляра приложения, который пере­дается в качестве параметра в функцию WinMain(), lpName – имя диалога, опреде­ленное в файле ресурсов, hwnd — дескриптор родительского окна для диалога, а lpDFunc – указатель на функцию диалога. Функция диалога в данном случае должна быть описана так же, как и для модального диалога.

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

Для завершения немодального диалога программа должна вызвать функцию DestroyWindow(), а не EndDialog(). Прототип функции DestroyWindow() имеет следую­щий вид:

BOLL DestroyWindow(HWND hwnd);

Параметр hwnd должен задавать дескриптор закрываемого окна (в данном случае диалога).

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

BOOL IsDialogMessage(HWND hdwnd, LPMSG msg);

Здесь hdwnd содержит дескриптор окна немодального диалога, a msg – сообще­ние, полученное в функции GetMessage(). Эта функция возвращает ненулевое значение, если сообщение предназначено для диалога, и нуль в противном случае. Если сообщение предназначено для диалога, оно будет автоматически направлено ему. Таким образом, для работы с немодальным диалогом цикл обработки сообщений Вашей программы должен выглядеть следующим образом:

while(GetMessage(&msg,NULL,0,0))

if(!IsDialogMessage(hDlg,&msg))

if(!TranslateAccelerator(hwnd,hAccel,&msg))

{

TranslateMessage(&msg); // использ.клавиатуры

DispatchMessage (&msg); // возврат к Windows

}

Как видите, сообщение обрабатывается обычным образом только в том случае, если оно не предназначено для диалога.

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

// Пример файла ресурсов, описывающего меню и диалог

#include "Mydialog.h"

#include <Windows.h>

MYMENU MENU

{

MENUITEM "Диалог &1", IDM_DIALOG1

MENUITEM "Диалог &2", IDM_DIALOG2

MENUITEM "Помощь", IDM_HELP

}

MYMENU ACCELERATORS

{

VK_F2, IDM_DIALOG1, VIRTKEY

VK_F3, IDM_DIALOG2, VIRTKEY

VK_F1, IDM_HELP, VIRTKEY

}

MYDB DIALOG 18, 18, 142, 92

CAPTION "Первый диалог"

STYLE DS_MODALFRAME|WS_POPUP|WS_CAPTION|WS_SYSMENU|

WS_VISIBLE

{

DEFPUSHBUTTON "Красный", IDD_RED, 57, 45, 36, 14,

WS_CHILD|WS_VISIBLE|WS_TABSTOP

PUSHBUTTON "Зеленый", IDD_GREEN, 95, 45, 36, 14,

WS_CHILD|WS_VISIBLE|WS_TABSTOP

PUSHBUTTON "Сброс", IDCANCEL, 52, 65, 37, 14,

WS_CHILD|WS_VISIBLE|WS_TABSTOP

PUSHBUTTON "Выбери фрукт", IDD_SELFRUIT,

2, 45, 50, 14, WS_CHILD|

WS_VISIBLE|WS_TABSTOP

LISTBOX ID_LB1, 2, 10, 47, 28, LBS_NOTIFY|WS_CHILD|

WS_VISIBLE| WS_BORDER|WS_VSCROLL|

WS_TABSTOP

EDITTEXT ID_EB1, 68, 8, 72, 12, ES_LEFT|

ES_AUTOHSCROLL|WS_CHILD|WS_VISIBLE|

WS_BORDER|WS_TABSTOP

PUSHBUTTON "Конец ввода", IDOK, 68, 22, 60, 14,

WS_CHILD|WS_VISIBLE|WS_TABSTOP

}

Далее в программу необходимо внести следующие изменения:

1) вызвать IsDialogMessage() в цикле обработки сообщений.

2) создать диалог, используя функцию CreateDialog(), а не функцию DialogBox().

3) для закрытия диалога заменить функцией DestroyWindows() функцию EndDialog().

Пример 5-4. Полный текст программы, использующей немодальный диалог (с внесенными изменениями), приводится ниже. Пример работы программы приведен на рис. 5.4. Обязательно попробуйте запустить эту программу, чтобы полностью понять разницу между модальным и немодальным диалогами.

Рис. 5.4. В немодальном режиме основная программа и диалог

работают параллельно

// Демонстрация немодального диалога

#include <Windows.h>

#include <String.h>

#include <Stdio.h>

#include "Mydialog.h"

LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM); BOOL CALLBACK DialogFunc(HWND,UINT,WPARAM,LPARAM);

char szWinName[]="МоеОкно"; // Имя класса окна

HINSTANCE hInst;

HWND hDlg; // Дескриптор окна диалога

int WINAPI WinMain(HINSTANCE hThisInst,

HINSTANCE hPrevInst,

LPSTR lpszArgs,

int nWinMode)

{

HWND hwnd;

MSG msg;

WNDCLASS wcl;

HACCEL hAccel;

// Определить класс окна

wcl.hInstance=hThisInst; // Дескриптор приложения

wcl.lpszClassName=szWinName; // Имя класса окна

wcl.lpfnWndProc=WindowFunc; // функция окна

wcl.style=0; // Стиль по умолчанию

wcl.hIcon=LoadIcon(NULL,IDI_APPLICATION); // Иконка

wcl.hCursor=LoadCursor(NULL,IDC_ARROW); // Курсор

wcl.lpszMenuName="MYMENU"; // Меню

wcl.cbClsExtra=0; // Без дополнит. информации

wcl.cbWndExtra=0;

wcl.hbrBackground // Заполнение окна белым цветом

=(HBRUSH)GetStockObject(WHITE_BRUSH);

if(!RegisterClass(&wcl))

return 0; // Зарегистрировать класс окна

// Создать окно:

hwnd=CreateWindow(szWinName, // Имя класса

"Вызов немодального диалога", // Загол.

WS_OVERLAPPEDWINDOW, // Стиль окна

CW_USEDEFAULT, // Х-координата

CW_USEDEFAULT, // Y-координата

CW_USEDEFAULT, // Ширина по умолчанию

CW_USEDEFAULT, // Высота по умолчанию

HWND_DESKTOP, // Нет родительского окна

NULL, // Нет меню

hThisInst, // Дескриптор приложения

NULL); // Без дополнительных аргументов

hInst=hThisInst; // Сохранить дескриптор текущего

// Загрузить акселераторы:

hAccel=LoadAccelerators(hThisInst,"MYMENU");

// Показать окно и перерисовать содержимое:

ShowWindow(hwnd,nWinMode);

UpdateWindow(hwnd);

// Запустить цикл обработки сообщений:

while(GetMessage(&msg,NULL,0,0))

if(!IsDialogMessage(hDlg,&msg))

if(!TranslateAccelerator(hwnd,hAccel,&msg))

{

TranslateMessage(&msg);// Исп. клавиатуру

DispatchMessage (&msg);//Возврат к Windows

}

return msg.wParam;

}

// Следующая функция вызывается ОС Windows и получает

// в качестве параметров сообщения из очереди

// сообщений данного приложения

LRESULT CALLBACK WindowFunc(HWND hwnd,

UINT message,

WPARAM wParam,

LPARAM lParam)

{

switch(message)

{

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDM_DIALOG1:

hDlg=CreateDialog(hInst,"MYDB",hwnd,

DialogFunc);

break;

case IDM_DIALOG2:

MessageBox(hwnd,

"Работает параллельно с первым",

"Второй диалог", MB_OK);

break;

case IDM_HELP:

MessageBox(hwnd, "Помощь",

"Помощь", MB_OK);

break;

}

break;

case WM_DESTROY: /* завершение программы */

PostQuitMessage(0);

break;

default: // Все сообщения, не обрабатываемые

// в данной функции, направляются

// на обработку по умолчанию

return DefWindowProc(hwnd, message,

wParam, lParam);

}

return 0;

}

// Простая функция диалога

BOOL CALLBACK DialogFunc(HWND hdwnd,

UINT message,

WPARAM wParam,

LPARAM lParam)

{

long i;

char str[80];

switch(message)

{

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDCANCEL:

DestroyWindow(hdwnd);

return 1;

case IDD_RED:

MessageBox(hdwnd,

"Выбран Красный",

"Красный",MB_OK);

return 1;

case IDD_GREEN:

MessageBox(hdwnd,

"Выбран Зеленый",

"Зеленый",MB_OK);

return 1;

case ID_LB1: // Сообщение от списка, если

// это, конечно, LBN_DBLCLK

if(HIWORD(wParam) == LBN_DBLCLK)

{ // Получ. индекс выбран. элемента

i=SendDlgItemMessage(hdwnd, ID_LB1,

LB_GETCURSEL,

0, 0L);

sprintf

(str,

"Индекс выбранного элемента %d",

i);

MessageBox(hdwnd,str,"Сделан выбор",

MB_OK);

}

return 1;

case IDD_SELFRUIT: //Кнопка "Выбери фрукт"

i=SendDlgItemMessage(hdwnd,ID_LB1,

LB_GETCURSEL,

0, 0L);

if( i > -1)

sprintf

(str,

"Индекс выбранного элемента %d",

i);

else

sprintf(str,"Фрукт не выбран");

MessageBox(hdwnd,str,"Сделан выбор",

MB_OK);

return 1;

case IDOK: // Кнопка IDOK "Конец ввода"

GetDlgItemText(hdwnd,ID_EB1,str,80);

MessageBox(hdwnd, str, "Содержимое окна ввода",

MB_OK);

return 1;

}

case WM_INITDIALOG: // Инициализация списка

SendDlgItemMessage(hdwnd, ID_LB1,

LB_ADDSTRING,

0, (LPARAM)"Яблоко");

SendDlgItemMessage(hdwnd, ID_LB1,

LB_ADDSTRING,

0, (LPARAM)"Апельсин");

SendDlgItemMessage(hdwnd, ID_LB1,

LB_ADDSTRING,

0, (LPARAM)"Груша");

SendDlgItemMessage(hdwnd, ID_LB1,

LB_ADDSTRING,

0, (LPARAM)"Виноград");

return 1;

}

return 0;

}

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