Программирование для 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 |