Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система Microsoft Windows 3.1 для программиста

© Александр Фролов, Григорий Фролов
Том 12, М.: Диалог-МИФИ, 1993, 255 стр.

[Назад] [Содеожание] [Дальше]

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

Другой вид диалоговых панелей, который мы рассмотрим, это немодальные диалоговые панели (modeless dialog boxes).

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

Немодальные диалоговые панели очень удобны для объединения различных инструментальных средств, предназначенных для работы с объектом, расположенным в главном окне или в дочернем окне, созданным главным окном приложения. На рис. 3.8 изображено главное приложение графического редактора PhotoFinish, созданного фирмой ZSoftCorporation, содержащее три немодальные диалоговые панели.

Рис. 3.8. Немодальные диалоговые панели в приложении PhotoFinish

С помощью диалоговой панели "Tools" вы можете выбирать средства для рисования или редактирования изображения, диалоговая панель "Width" предназначена для выбора размеров инструмента, а панель 'Palette" - для выбора цветовой палитры.

Все эти три немодальные диалоговые панели работают параллельно с главным окном приложения и дочерним окном, в котором редактируется графическое изображение.

Многие другие приложения Windows используют немодальные диалоговые панели, например, для выполнения операций поиска и замены символьных строк.

Создание и уничтожение немодальных диалоговых панелей

Для создания немодальных диалоговых панелей используются описанные нами ранее функции CreateDialog, CreateDialogParam, CreateDialogIndirect, CreateDialogIndirectParam.

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

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

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

Изменения в цикле обработки сообщений

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

Для разделения этих сообщений цикл обработки должен вызывать функцию IsDialogMessage:

BOOL WINAPI IsDialogMessage(HWND hwndDlg, MSG FAR* lpmsg);

Функция IsDialogMessage определяет, предназначено ли сообщение, определяемое параметром lpmsg, для немодальной диалоговой панели с идентификатором окна, равным hwndDlg. Если предназначено, функция сама выполняет обработку такого сообщения и возвращает значение TRUE. В противном случае возвращается значение FALSE.

Приложение DIALOGNM

Приложение DIALOGNM панель, аналогичную той, что создается приложением DIALOG. Но теперь эта диалоговая панель создается как немодальная (рис. 3.9).

Рис. 3.9. Немодальная диалоговая панель в приложении DIALOGNM

Главный файл приложения DIALOGNM приведен в листинге 3.15.


Листинг 3.15. Файл dialognm\dialognm.cpp


// ----------------------------------------
// Простейшая немодальная диалоговая панель
// ----------------------------------------

#define STRICT
#include <windows.h>
#include <mem.h>

#define IDB_Button1 1

// Прототипы функций
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK    _export DlgProc(HWND, UINT, WPARAM, LPARAM);

// Имя класса окна
char const szClassName[]   = "DialogNMAppClass";

// Заголовок окна
char const szWindowTitle[] = "Modeless Dialog Box";

// Идентификатор окна диалоговой панели
HWND    hwndDlg;

// Идентификатор главного окна приложения
HWND    hwndMain;

HINSTANCE hInst;

// =====================================
// Функция WinMain
// =====================================
#pragma argsused

int PASCAL
WinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR     lpszCmdLine, 
        int       nCmdShow)   
{
  MSG  msg;   // структура для работы с сообщениями

  HWND hButton1;

  // Инициализируем приложение
  if(!InitApp(hInstance))
      return FALSE;

  hInst = hInstance;

  // После успешной инициализации приложения создаем
  // главное окно приложения
  hwndMain = CreateWindow(
    szClassName,         // имя класса окна
    szWindowTitle,       // заголовок окна
    WS_OVERLAPPEDWINDOW, // стиль окна
    CW_USEDEFAULT,       // задаем размеры и расположение
    CW_USEDEFAULT,       // окна, принятые по умолчанию 
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    0,                   // идентификатор родительского окна
    0,                   // идентификатор меню
    hInstance,           // идентификатор приложения
    NULL);               // указатель на дополнительные
                         // параметры

  // Если создать окно не удалось, завершаем приложение
  if(!hwndMain)
    return FALSE;

  // Рисуем главное окно
  ShowWindow(hwndMain, nCmdShow);
  UpdateWindow(hwndMain);

  // Создаем кнопку
  hButton1 = CreateWindow("button", "About...",
    WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
    20, 20,
    90, 30,
    hwndMain,
    (HMENU) IDB_Button1,
    hInstance, NULL);

  if(!hButton1)
    return FALSE;

  // До запуска цикла обработки сообщений
  // идентификатор диалоговой панели должен
  // быть равен 0, т. к. панель еще не создана 
  hwndDlg = (HWND)0;

  // Запускаем цикл обработки сообщений
  while(GetMessage(&msg, 0, 0, 0))
  {
    // Выделяем сообщения для диалоговой панели,
    // если эта панель уже создана
    if(hwndDlg == 0 || !IsDialogMessage(hwndDlg, &msg))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }
  return msg.wParam;
}

// =====================================
// Функция InitApp
// Выполняет регистрацию класса окна
// =====================================

BOOL
InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации
                  // класса окна

  memset(&wc, 0, sizeof(wc));

  wc.style = 0;
  wc.lpfnWndProc = (WNDPROC) WndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszMenuName = (LPSTR)NULL;
  wc.lpszClassName = (LPSTR)szClassName;

  // Регистрация класса
  aWndClass = RegisterClass(&wc);

  return (aWndClass != 0);
}

// =====================================
// Функция WndProc
// =====================================

LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static DLGPROC lpfnDlgProc;

  switch (msg)
  {
    case WM_COMMAND:
    {
      // Если нажата кнопка, выводим
      // диалоговую панель
      if(wParam == IDB_Button1)
      {
        // Переходник для функции диалоговой панели
        lpfnDlgProc = 
          (DLGPROC)MakeProcInstance((FARPROC)DlgProc, hInst);

        // Создаем немодальную диалоговую панель
        hwndDlg = CreateDialog(hInst, "DIALOG_OK",
                  hwnd, lpfnDlgProc);
      }
      return 0;
    }

    case WM_DESTROY:
    {


// Удаляем диалоговую панель
      DestroyWindow(hwndDlg);

      PostQuitMessage(0);
      return 0;
    }
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

// =====================================
// Функция DlgProc
// =====================================
#pragma argsused

BOOL CALLBACK _export
DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    // Инициализация диалоговой панели
    case WM_INITDIALOG:
    {
      return TRUE;
    }

    case WM_COMMAND:
    {
      switch(wParam)
      {
        // Сообщение от кнопки "OK"
        case IDOK:

        // Отмена диалоговой панели.
        // Это сообщение приходит, когда пользователь
        // нажимает на клавишу <Esc>
        case IDCANCEL:
        {
          // Уничтожаем диалоговую панель
          DestroyWindow(hdlg);

          // Завершаем работу приложения
          DestroyWindow(hwndMain);
          return TRUE;
        }
      }
    }
  }
  return FALSE;
}

Функция WinMain приложения DIALOGNM аналогична функции WinMain приложения DIALOG. Она создает главное окно приложения, в котором располагает кнопку 'About...", вслед за чем запускает цикл обработки сообщений.

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

hwndDlg = (HWND)0;
while(GetMessage(&msg, 0, 0, 0))
{
  if(hwndDlg == 0 || !IsDialogMessage(hwndDlg, &msg))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
}

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

Когда немодальная диалоговая панель будет создана, идентификатор ее окна будет записан в переменную hwndDlg. После этого в работу включится функция IsDialogMessage. Она будет "вылавливать" в очереди приложения сообщения, предназначенные для диалоговой панели hwndDlg и выполнять их обработку. Все остальные сообщения будут обработаны обычным образом функциями TranslateMessage и DispatchMessage.

Функция главного окна приложения обрабатывает сообщение WM_COMMAND, поступающее от кнопки 'About...". В ответ на это сообщение создается немодальная диалоговая панель, для чего вызывается функция CreateDialog:

hwndDlg = CreateDialog(hInst,"DIALOG_OK", hwnd, lpfnDlgProc);

Идентификатор окна созданной диалоговой панели записывается в глобальную переменную hwndDlg, после чего в цикле обработки сообщений начинает действовать функция IsDialogMessage.

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

case WM_DESTROY:
{
  DestroyWindow(hwndDlg);
  PostQuitMessage(0);
  return 0;
}

Функция диалоговой панели обрабатывает сообщения WM_INITDIALOG и WM_COMMAND.

Обработка сообщения WM_INITDIALOG сводится к возвращению значения TRUE. Если приходит сообщение WM_COMMAND с идентификаторами IDOK или IDCANCEL, функция диалоговой панели завершает диалоговую панель, уничтожая свое окно и главное окно приложения:

case IDOK:
case IDCANCEL:
{
  DestroyWindow(hdlg);
  DestroyWindow(hwndMain);
  return TRUE;
}

Файл ресурсов приложения, содержащий шаблон немодальной диалоговой панели, приведен в листинге 3.16.


Листинг 3.16. Файл dialognm\dialognm.rc


#include "g:\bc\include\windows.h"

APPICON ICON "appicon.ico"

DIALOG_OK DIALOG 25, 34, 152, 67
STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
CAPTION "Приложение DIALOGNM"
BEGIN
        CTEXT "Microsoft Windows Application\n"
            "Приложение DIALOGNM\n"
            "(C) Frolov A.V., 1994", -1, 28, 9, 117, 26,
              WS_CHILD | WS_VISIBLE | WS_GROUP
        ICON "APPICON", -1, 6, 14, 16, 16, WS_CHILD | WS_VISIBLE
        DEFPUSHBUTTON "OK", IDOK, 56, 43, 36, 14,
              WS_CHILD | WS_VISIBLE | WS_TABSTOP
END

Обратите внимание на стиль немодальной диалоговой панели:

STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE

В отличие от стиля модальной диалоговой панели приложения DIALOG, стиль немодальной диалоговой панели приложения DIALOGNM содержит константу WS_VISIBLE и не содержит константы DS_MODALFRAME.

В файле ресурсов кроме шаблона диалоговой панели есть ссылка на пиктограмму (листинг 3.17).


Листинг 3.17. Файл dialognm\appicon.ico



Файл определения модуля приложения DIALOGNM приведен в листинге 3.18.


Листинг 3.18. Файл dialognm\dialognm.def


; =============================
; Файл определения модуля
; =============================
NAME DIALOGNM
DESCRIPTION 'Приложение DIALOGNM, (C) 1994, Frolov A.V.'
EXETYPE windows
STUB 'winstub.exe'
STACKSIZE 5120
HEAPSIZE 1024
CODE preload moveable discardable
DATA preload moveable multiple

[Назад] [Содеожание] [Дальше]