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

Программирование для IBM OS/2

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

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

3.5. Приложение MENUAPP

В приложении MENUAPP мы создадим стандартное меню верхнего уровня, показанное на рис. 3.5.

Рис. 3.5. Стандартное меню верхнего уровня в приложении MENUAPP

Временное меню Options, показанное на рис. 3.6, демонстрирует использование стилей меню MIS_BREAKSEPARATOR и MIS_STATIC , а также атрибута строки меню MIA_FRAMED .

Рис. 3.6. Временное меню Options

Если в окне Client Window сделать щелчок правой клавишей мыши, около курсора появится плавающее меню, которое в точности повторяет временное меню File (рис. 3.7).

Рис. 3.7. Плавающее меню, повторяющее временное меню File

Исходный текст приложения MENUAPP представлен в листинге 3.1.

Листинг 3.1. Файл menuapp\menuapp.c

// ===================================================
// Определения
// ===================================================

#define INCL_WIN
#define INCL_GPI
#define INCL_WINDIALOGS

#include <os2.h>
#include <stdio.h>
#include "menuapp.h"

// Прототип функции окна приложения
MRESULT EXPENTRY WndProc(HWND, ULONG, MPARAM, MPARAM);

// ===================================================
// Глобальные переменные
// ===================================================

// Идентификатор Anchor-block
HAB  hab;

// Идентификатор окна Frame Window 
HWND hWndFrame;

// Идентификатор окна Client Window 
HWND hWndClient;

// Заголовок приложения
CHAR szAppTitle[] = "Menu Demo Application";

// Идентификатор временного меню
HWND    hwndPopupMenu;

// ===================================================
// Главная функция приложения main 
// ===================================================

int main ()
{
  // Идентификатор очереди сообщений
  HMQ   hmq;

  // Структура, в которую записывается сообщение,
  // извлеченное из очереди
  QMSG   qmsg;

  // Переменная для хранения кода возврата
  BOOL  fRc;

  // Флаги для создания окна Frame Window 
  ULONG flFrameFlags =
    FCF_SYSMENU    | FCF_TITLEBAR       | FCF_MINMAX   |
    FCF_SIZEBORDER | FCF_SHELLPOSITION | FCF_TASKLIST |
    FCF_ICON | FCF_MENU;

  // Имя класса главного окна
  CHAR  szWndClass[] = "MENUDEMO";

  // Инициализация приложения, необходимая для 
  // использования функций Presentation Manager
  hab = WinInitialize (0);

  if(hab == NULLHANDLE)
  {
    WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка инициализации",
      "Ошибка", 0, MB_ICONHAND | MB_OK);
    return(-1);
  }

  // Создаем очередь сообщений
  hmq = WinCreateMsgQueue (hab, 0);

  if(hmq == NULLHANDLE)
  {
    WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при создании очереди сообщений",
      "Ошибка", 0, MB_ICONHAND | MB_OK);

    WinTerminate (hab);
    return(-1);
  }

  // Регистрация главного окна приложения
  fRc = WinRegisterClass (hab, szWndClass, 
    (PFNWP)WndProc, 0, 0);

  if(fRc == FALSE)
  {
    WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при регистрации класса главного окна",
      "Ошибка", 0, MB_ICONHAND | MB_OK);

    WinDestroyMsgQueue (hmq);
    WinTerminate (hab);

    return(-1);
  }

  // Создаем главное окно приложения
  hWndFrame = WinCreateStdWindow (HWND_DESKTOP, 
    WS_VISIBLE ,
    &flFrameFlags, szWndClass, szAppTitle,
    0, 0, ID_APP_FRAMEWND, &hWndClient);

  if(hWndFrame == NULLHANDLE)
  {
    WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при создании главного окна",
      "Ошибка", 0, MB_ICONHAND | MB_OK);

    WinDestroyMsgQueue (hmq);
    WinTerminate (hab);

    return(-1);
  }

  // Запускаем цикл обработки сообщений
  while(WinGetMsg (hab, &qmsg, 0, 0, 0))
    WinDispatchMsg (hab, &qmsg);

  // Уничтожаем главное окно приложения
  WinDestroyWindow(hWndFrame);

  // Удаляем очередь сообщений и вызываем
  // функцию WinTerminate 
  WinDestroyMsgQueue (hmq);
  WinTerminate (hab);

  // Возвращаем управление операционной системе
  return(0);
}

// ===================================================
// Функция главного окна приложения
// ===================================================

MRESULT EXPENTRY
WndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
  // Временный буфер для подготовки сообщения
  CHAR szMsg[100];

  USHORT  usItemId; // идентификатор меню
  HWND    hwndMenu; // идентификатор окна меню

  switch (msg)
  {
    case WM_ERASEBACKGROUND :
      return(MRFROMLONG(1L));

    // Выполняем инициализацию главного меню приложения
    case WM_INITMENU :
    {
      // Идентификатор меню
      usItemId = SHORT1FROMMP (mp1);

      // Идентификатор окна меню
      hwndMenu = HWNDFROMMP(mp2);

      // В меню File блокируем строки New и Open
      if(usItemId == IDM_FILE)
      {
        WinEnableMenuItem(hwndMenu, IDM_FILE_NEW,
          FALSE);
        WinEnableMenuItem(hwndMenu, IDM_FILE_OPEN, 
          FALSE);
      }

      // В меню Edit блокируем строки Undo и Redo
      else if(usItemId == IDM_EDIT)
      {
        WinEnableMenuItem(hwndMenu, IDM_EDIT_UNDO, 
          FALSE);
        WinEnableMenuItem(hwndMenu, IDM_EDIT_REDO, 
          FALSE);
      }
      return(WinDefWindowProc (hWnd, msg, mp1, mp2));
    }

    // Сообщение WM_COMMAND  поступает в функцию окна,
    // кодгда пользователь выбирает одну из строк меню
    case WM_COMMAND :
    {
      // Анализируем код строки меню
      switch(LOUSHORT(mp1))
      {
        case IDM_FILE_NEW:
        case IDM_FILE_OPEN:
        case IDM_FILE_SAVE:
        case IDM_FILE_SAVEAS:

        case IDM_EDIT_UNDO:
        case IDM_EDIT_REDO:
        case IDM_EDIT_CUT:
        case IDM_EDIT_COPY:
        case IDM_EDIT_PASTE:
        case IDM_EDIT_CLEAR:
        case IDM_EDIT_DUPLICATE:
        case IDM_EDIT_SELECTALL:

        case IDM_OPTIONS_FONT_NORMAL:
        case IDM_OPTIONS_FONT_BOLD:
        case IDM_OPTIONS_FONT_ITALIC:
        case IDM_OPTIONS_FONT_UNDERLINE:
        case IDM_OPTIONS_PARA_LEFT:
        case IDM_OPTIONS_PARA_CENTER:
        case IDM_OPTIONS_PARA_RIGHT:
        case IDM_OPTIONS_PARA_JUSTIFY:

        case IDM_HELP_INDEX:
        case IDM_HELP_GENERAL:
        case IDM_HELP_USING:
        case IDM_HELP_KEYS:
        {
           WinMessageBox (HWND_DESKTOP, hWnd,
             "Функция не реализована",
             szAppTitle, 0, MB_INFORMATION | MB_OK);
          break;
        }

        case IDM_HELP_ABOUT:
        {
           WinMessageBox (HWND_DESKTOP, hWnd,
             "Приложение MenuApp, (C) Frolov A., 1996",
             szAppTitle, 0, MB_INFORMATION | MB_OK);
          break;
        }

        // Если из меню File выбрана строка Exit,
        // завершаем работу приложения
        case IDM_FILE_EXIT:
        {
           WinPostMsg (hWnd, WM_QUIT , 0L, 0L);
           break;
        }
      }
      return(WinDefWindowProc (hWnd, msg, mp1, mp2));

    }

    // В процессе инициализации главного окна 
    // приложения загружаем временное меню и 
    // определяем идентфикатор его окна
    case WM_CREATE :
    {
      hwndPopupMenu = WinLoadMenu (hWnd,
        NULLHANDLE, POPUP_MENU);
      return FALSE;
    }

    // Перед уничтожением главного окна приложения
    // уничтожаем окно временного меню
    case WM_DESTROY :
    {
      WinDestroyWindow(hwndPopupMenu);
      break;
    }

    // Если пользователь сделал в окне приложения 
    // щелчок правой клавишей мыши, отображаем 
    // временное меню
    case WM_BUTTON2DOWN :
    {
      WinPopupMenu (hWnd, hWnd, hwndPopupMenu,
        SHORT1FROMMP (mp1), SHORT2FROMMP (mp1),
        IDM_FILE_NEW,
        PU_POSITIONONITEM | PU_HCONSTRAIN | 
        PU_VCONSTRAIN |
        PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2 | 
        PU_KEYBOARD);

      return 0;
    }

    default:
      return(WinDefWindowProc (hWnd, msg, mp1, mp2));
  }
  return(WinDefWindowProc (hWnd, msg, mp1, mp2));
}

Глобальные переменные

В области глобальных переменных определены идентификаторы окон FrameWindow и ClientWindow (соответственно, переменные hWndFrame и hWndClient), заголовок приложения szAppTitle.

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

Функция main

В функции main приложения MENUAPP нет ничего необычного. Так как мы будем использовать меню верхнего уровня, определенное в ресурсах приложения, среди флагов окна Frame Window указан флаг FCF_MENU :

ULONG flFrameFlags =
    FCF_SYSMENU    | FCF_TITLEBAR       | FCF_MINMAX   |
    FCF_SIZEBORDER | FCF_SHELLPOSITION | FCF_TASKLIST |
    FCF_ICON | FCF_MENU;

Так как при создании главного окна приложения мы указали функции WinCreateStdWindow идентификатор ресурсов ID_APP_FRAMEWND, меню верхнего уровня также должно иметь этот идентификатор.

Функция окна WndProc

Функция главного окна приложения WndProc обрабатывает два сообщения, поступающие от меню. Это сообщения WM_INITMENU и WM_COMMAND .

Сообщение WM_INITMENU

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

Для временного меню File обработчик сообщения WM_INITMENU выполняет блокировку строк New и Open, вызывая функцию WinEnableMenuItem. Во временном меню Edit аналогичным образом блокируются строки Undo и Redo.

Сообщение WM_COMMAND

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

Тем не менее, при выборе строки Product Information из меню Help на экране повляется информация о разработчике приложения. Если же из меню File выбрать строку Exit, с помощью функции WinPostMsg в очередь приложения будет записано сообщение WM_QUIT . Это приведет к тому, что при его выборке из очереди цикл обработки будет завершен. В результате приложение также завершит свою работу.

Сообщение WM_CREATE

В процессе создания главного окна приложения его функция получает сообщение WM_CREATE . Обработчик этого сообщения загружает из ресурсов приложения временное меню, описанное с идентификатором POPUP_MENU. Для этого он использует функцию WinLoadMenu :

case WM_CREATE :
{
  hwndPopupMenu = WinLoadMenu (hWnd,
     NULLHANDLE, POPUP_MENU);
  return FALSE;
}

Меню с идентификатором POPUP_MENU будет использовано в качестве плавающего. Оно будет появляться по щелчку правой клавишей мыши в окне приложения.

Сообщение WM_DESTROY

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

case WM_DESTROY :
{
  WinDestroyWindow(hwndPopupMenu);
  break;
}

Сообщение WM_BUTTON2DOWN

Отображение загруженного ранее плавающего меню выполняется с помощью функции WinPopupMenu :

case WM_BUTTON2DOWN :
{
  WinPopupMenu (hWnd, hWnd, hwndPopupMenu,
    SHORT1FROMMP (mp1), SHORT2FROMMP (mp1),
    IDM_FILE_NEW,
    PU_POSITIONONITEM | PU_HCONSTRAIN | PU_VCONSTRAIN |
    PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2 | PU_KEYBOARD);
  return 0;
}

В качестве идентификаторов родительского окна и окна-владельца мы указали значение hWnd - идентификатор, полученный функцией окна.

Функция WinPopupMenu отображает меню с идентификатором hwndPopupMenu, полученным при загрузке меню в обработчике сообщения WM_CREATE .

Для отображения меню используются координаты курсора мыши, которые передаются в параметре mp1 сообщения WM_BUTTON2DOWN . Эти координаты извлекаются из параметра mp1 с помощью макрокоманд SHORT1FROMMP (координата X) и SHORT2FROMMP (координата Y).

Так как в дополнительных параметрах указано значение PU_POSITIONONITEM, при отображении будет выделена строка с идентификатором IDM_FILE_NEW (строка New плавающего меню).

Для того чтобы вне зависимости от расположения курсора мыши во время щелчка в окне приложения плавающее меню полностью поместилось на экране, мы указали значения PU_HCONSTRAIN и PU_VCONSTRAIN .

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

Файл menuapp.h

В файле menuapp.h (листинг 3.2) сделаны определения всех необходимых констант, таких как идентификатор ресурсов главного окна приложения ID_APP_FRAMEWND, а также идентификаторы временных меню, идентификаторы строк меню и идентификатор плавающего меню.

Листинг 3.2. Файл menuapp\menuapp.h

#define ID_APP_FRAMEWND 1

#define IDM_FILE        100
#define IDM_FILE_NEW    101
#define IDM_FILE_OPEN   102
#define IDM_FILE_SAVE   103
#define IDM_FILE_SAVEAS 104
#define IDM_FILE_EXIT   105

#define IDM_EDIT        200
#define IDM_EDIT_UNDO   201
#define IDM_EDIT_REDO   202
#define IDM_EDIT_CUT    203
#define IDM_EDIT_COPY   204
#define IDM_EDIT_PASTE  205
#define IDM_EDIT_CLEAR  206
#define IDM_EDIT_DUPLICATE 207
#define IDM_EDIT_SELECTALL 208

#define IDM_HELP           300
#define IDM_HELP_INDEX     301
#define IDM_HELP_GENERAL   302
#define IDM_HELP_USING     303
#define IDM_HELP_KEYS      304
#define IDM_HELP_ABOUT     305

#define POPUP_MENU         400

#define IDM_OPTIONS                 500
#define IDM_OPTIONS_FONT_NORMAL     501
#define IDM_OPTIONS_FONT_BOLD       502
#define IDM_OPTIONS_FONT_ITALIC     503
#define IDM_OPTIONS_FONT_UNDERLINE  504

#define IDM_OPTIONS_PARA_LEFT       505
#define IDM_OPTIONS_PARA_CENTER     506
#define IDM_OPTIONS_PARA_RIGHT      507
#define IDM_OPTIONS_PARA_JUSTIFY    508

Файл ресурсов приложения MENUAPP

Файл ресурсов приложения MENUAPP представлен в листинге 3.3.

Листинг 3.3. Файл menuapp\menuapp.rc

#include <os2.h>
#include "menuapp.h"

ICON ID_APP_FRAMEWND MENUAPP.ICO

MENU ID_APP_FRAMEWND
BEGIN
  SUBMENU "~File",          IDM_FILE
    BEGIN
	MENUITEM  "~New...",     IDM_FILE_NEW
	MENUITEM  "~Open...",    IDM_FILE_OPEN
	MENUITEM  SEPARATOR
	MENUITEM  "~Save...",    IDM_FILE_SAVE
	MENUITEM  "Save ~as...", IDM_FILE_SAVEAS
	MENUITEM  SEPARATOR
	MENUITEM  "~Exit",       IDM_FILE_EXIT
    END

  SUBMENU "~Edit",          IDM_EDIT
    BEGIN
	MENUITEM  "~Undo",       IDM_EDIT_UNDO
	MENUITEM  "~Redo",       IDM_EDIT_REDO
	MENUITEM  SEPARATOR
	MENUITEM  "Cu~t",        IDM_EDIT_CUT
	MENUITEM  "~Copy",       IDM_EDIT_COPY
	MENUITEM  "~Paste",      IDM_EDIT_PASTE
	MENUITEM  "Cl~ear",      IDM_EDIT_CLEAR
	MENUITEM  "~Duplicate",  IDM_EDIT_DUPLICATE
	MENUITEM  SEPARATOR
	MENUITEM  "~Select all", IDM_EDIT_SELECTALL
    END

  SUBMENU "~Options", IDM_OPTIONS
    BEGIN
	MENUITEM  "Font",       -1, MIS_STATIC, MIA_FRAMED
	MENUITEM  "~Normal",      IDM_OPTIONS_FONT_NORMAL
	MENUITEM  "~Bold",        IDM_OPTIONS_FONT_BOLD
	MENUITEM  "~Italic",      IDM_OPTIONS_FONT_ITALIC
	MENUITEM  "~Underline",IDM_OPTIONS_FONT_UNDERLINE
	MENUITEM  "Alighnment", -1,
          MIS_BREAKSEPARATOR | MIS_STATIC, MIA_FRAMED
	MENUITEM  "~Left",        IDM_OPTIONS_PARA_LEFT
	MENUITEM  "~Center",      IDM_OPTIONS_PARA_CENTER
	MENUITEM  "~Right",       IDM_OPTIONS_PARA_RIGHT
	MENUITEM  "~Justify",     IDM_OPTIONS_PARA_JUSTIFY
    END

  SUBMENU "~Help", IDM_HELP
    BEGIN
	MENUITEM  "Help ~index...",      IDM_HELP_INDEX
	MENUITEM  "~General help...",    IDM_HELP_GENERAL
	MENUITEM  "~Using help...",      IDM_HELP_USING
	MENUITEM  "~Keys help...",       IDM_HELP_KEYS
	MENUITEM  SEPARATOR
	MENUITEM  "~Product information...",
         IDM_HELP_ABOUT
    END
END

MENU POPUP_MENU
BEGIN
  MENUITEM  "~New...",     IDM_FILE_NEW
  MENUITEM  "~Open...",    IDM_FILE_OPEN
  MENUITEM  SEPARATOR
  MENUITEM  "~Save...",    IDM_FILE_SAVE
  MENUITEM  "Save ~as...", IDM_FILE_SAVEAS
  MENUITEM  SEPARATOR
  MENUITEM  "~Exit",       IDM_FILE_EXIT
END

В меню верхнего уровня с идентификатором ID_APP_FRAMEWND определены четыре временных меню с идентификаторами IDM_FILE, IDM_EDIT, IDM_OPTIONS и IDM_HELP.

Временное меню IDM_OPTIONS отображается в виде таблицы, состоящей из двух столбцов, озаглавленных, соответственно, Font и Alighnment.

Строка Font имеет атрибуты MIS_STATIC и MIA_FRAMED , поэтому ее нельзя выбрать и вокруг этой строки нарисована рамка:

MENUITEM  "Font", -1, MIS_STATIC, MIA_FRAMED

Строка Alighnment дополнительно имеет атрибут MIS_BREAKSEPARATOR , поэтому она отображается в отдельном столбце:

MENUITEM  "Alighnment", -1,
          MIS_BREAKSEPARATOR | MIS_STATIC, MIA_FRAMED

В файле описания ресурсов приложения также определено плавающее меню с идентификатором POPUP_MENU, которое полностью повторяет временное меню File.

Файл определения модуля

Файл определения модуля приложения не имеет никаких особенностей и приведен в листинге 3.4.

Листинг 3.4. Файл menuapp\menuapp.def

NAME        MENUAPP   WINDOWAPI
DESCRIPTION 'MenuApp Application (C) Frolov A., 1996'
HEAPSIZE    4096
STACKSIZE   32768
EXPORTS     WndProc
[Назад] [Содеожание] [Дальше]