Операционная система Microsoft Windows 3.1 для программиста© Александр Фролов, Григорий ФроловТом 13, М.: Диалог-МИФИ, 1993, 284 стр. 1.14. Приложение GMENUВ заключение первой главы, посвященной меню, приведем приложение GMENU, которое демонстрирует использование графики в меню. Меню верхнего уровня приложения GMENU содержит временное меню "LineStyle", которое используется для выбора одного из стилей линии (рис. 1.21).
Рис. 1.21. Графические изображения bitmap в строках меню В данном случае использование графики из-за большей наглядности предпочтительнее текстового описания внешнего вида линий, такого как "тонкая линия", "толстая линия", пунктирная линия" и "волнистая линия". Мы также создали собственный символ для отметки строки меню в виде закрашенного кружка (рис. 1.22).
Рис. 1.22. Отметка строки меню при помощи графического изображения bitmap Главный файл приложения GMENU приведен в листинге 1.16. Листинг 1.16. Файл gmenu/gmenu.cpp // ---------------------------------------------- // Использование графических изображений в меню // ---------------------------------------------- #define STRICT #include <windows.h> #include <mem.h> #include "gmenu.hpp" // Прототипы функций BOOL InitApp(HINSTANCE); LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM); // Имя класса окна char const szClassName[] = "GMenuClass"; // Заголовок окна char const szWindowTitle[] = "Menu Demo"; // Идентификатор меню верхнего уровня HMENU hmenu; // Идентификаторы временных меню HMENU hmenuFile; // "File" HMENU hmenuLineStyle; // "Edit" HMENU hmenuHelp; // "Help" // Идентификаторы графических изображений для строк меню HBITMAP hbmpLine1; HBITMAP hbmpLine2; HBITMAP hbmpLine3; HBITMAP hbmpLine4; HBITMAP hbmpLineStyle; HBITMAP hbmpChecked; HBITMAP hbmpUnchecked; // Идентификатор текущей копии приложения HINSTANCE hInst; // ===================================== // Функция WinMain // ===================================== #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложения // Инициализируем приложение if(!InitApp(hInstance)) return FALSE; // Сохраняем идентификатор текущей копии приложения hInst = hInstance; // После успешной инициализации приложения создаем // главное окно приложения hwnd = CreateWindow( szClassName, // имя класса окна szWindowTitle, // заголовок окна WS_OVERLAPPEDWINDOW, // стиль окна CW_USEDEFAULT, // задаем размеры и расположение CW_USEDEFAULT, // окна, принятые по умолчанию CW_USEDEFAULT, CW_USEDEFAULT, 0, // идентификатор родительского окна 0, // идентификатор меню hInstance, // идентификатор приложения NULL); // указатель на дополнительные // параметры // Если создать окно не удалось, завершаем приложение if(!hwnd) return FALSE; // Рисуем главное окно ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); // Запускаем цикл обработки сообщений while(GetMessage(&msg, 0, 0, 0)) { DispatchMessage(&msg); } return msg.wParam; } // ===================================== // Функция InitApp // Выполняет регистрацию класса окна // ===================================== BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна // Записываем во все поля структуры нулевые значения memset(&wc, 0, sizeof(wc)); wc.lpszMenuName = NULL; 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.lpszClassName = (LPSTR)szClassName; // Регистрация класса aWndClass = RegisterClass(&wc); return (aWndClass != 0); } // ===================================== // Функция WndProc // ===================================== LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: { // Загружаем изображения строк меню hbmpLine1 = LoadBitmap(hInst, "LINE1"); hbmpLine2 = LoadBitmap(hInst, "LINE2"); hbmpLine3 = LoadBitmap(hInst, "LINE3"); hbmpLine4 = LoadBitmap(hInst, "LINE4"); hbmpLineStyle = LoadBitmap(hInst, "LINESTYLE"); hbmpChecked = LoadBitmap(hInst, "CHECKED"); hbmpUnchecked = LoadBitmap(hInst, "UNCHECKED"); // Создаем пустое меню верхнего уровня hmenu = CreateMenu(); // Подключаем меню к главному окну приложения SetMenu(hwnd, hmenu); // Создаем временные меню hmenuFile = CreatePopupMenu(); hmenuHelp = CreatePopupMenu(); hmenuLineStyle = CreatePopupMenu(); // Добавляем строки к меню "File" AppendMenu(hmenuFile, MF_ENABLED | MF_STRING, CM_FILENEW, "&New"); AppendMenu(hmenuFile, MF_ENABLED | MF_STRING, CM_FILEOPEN, "&Open"); AppendMenu(hmenuFile, MF_ENABLED | MF_STRING, CM_FILECLOSE, "&Close"); AppendMenu(hmenuFile, MF_ENABLED | MF_STRING, CM_FILESAVE, "&Save"); AppendMenu(hmenuFile, MF_ENABLED | MF_STRING, CM_FILESAVEAS, "Save &as..."); AppendMenu(hmenuFile, MF_SEPARATOR, 0, NULL); AppendMenu(hmenuFile, MF_DISABLED | MF_STRING, CM_FILEDEMO, "&Demo Version"); AppendMenu(hmenuFile, MF_SEPARATOR, 0, NULL); AppendMenu(hmenuFile, MF_ENABLED | MF_STRING, CM_FILEEXIT, "E&xit"); // Для строки "Demo Version" меню "File" определяем // изображения, которые будут использоваться для // вывода строки в отмеченном и неотмеченном состоянии SetMenuItemBitmaps(hmenuFile, CM_FILEDEMO, MF_BYCOMMAND, hbmpUnchecked, hbmpChecked); // Отмечаем строку "Demo Version" CheckMenuItem(hmenuFile, CM_FILEDEMO, MF_BYCOMMAND | MF_CHECKED); // Добавляем строки к меню "Line Style". // Вместо текстовых строк используем графические // изображения bitmap AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP, CM_LINE1, (LPCSTR)(DWORD)hbmpLine1); AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP, CM_LINE2, (LPCSTR)(DWORD)hbmpLine2); AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP, CM_LINE3, (LPCSTR)(DWORD)hbmpLine3); AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP, CM_LINE4, (LPCSTR)(DWORD)hbmpLine4); // Добавляем строки к меню "Help" AppendMenu(hmenuHelp, MF_GRAYED | MF_STRING, CM_HELPINDEX, "&Index\tF1"); AppendMenu(hmenuHelp, MF_GRAYED | MF_STRING, CM_HELPKEYBOARD, "&Keyboard"); AppendMenu(hmenuHelp, MF_GRAYED | MF_STRING, CM_HELPCOMMANDS, "&Commands"); AppendMenu(hmenuHelp, MF_GRAYED | MF_STRING, CM_HELPPROCEDURES, "&Procedures"); AppendMenu(hmenuHelp, MF_GRAYED | MF_STRING, CM_HELPUSING_HELP, "&Using help"); AppendMenu(hmenuHelp, MF_SEPARATOR, 0, NULL); AppendMenu(hmenuHelp, MF_ENABLED | MF_STRING, CM_HELPABOUT, "&About..."); // Добавляем временные меню к меню верхнего уровня AppendMenu(hmenu, MF_ENABLED | MF_POPUP, (UINT)hmenuFile, "&File"); // Для временного меню "Line Style" используем // изображение bitmap AppendMenu(hmenu, MF_ENABLED | MF_POPUP | MF_BITMAP, (UINT)hmenuLineStyle, (LPCSTR)(DWORD)hbmpLineStyle); AppendMenu(hmenu, MF_ENABLED | MF_POPUP, (UINT)hmenuHelp, "&Help"); // Перерисовываем меню DrawMenuBar(hwnd); return 0; } case WM_COMMAND: { switch (wParam) { // Сообщения от меню case CM_HELPUSING_HELP: case CM_HELPPROCEDURES: case CM_HELPCOMMANDS: case CM_HELPKEYBOARD: case CM_HELPINDEX: case CM_FILESAVEAS: case CM_FILESAVE: case CM_FILEOPEN: case CM_FILENEW: case CM_FILECLOSE: { // Выводим сообщение об ошибке MessageBox(hwnd, "Функция не реализована", NULL, MB_OK); return 0; } // Выбрали строку "About..." в меню "Help" case CM_HELPABOUT: { MessageBox(hwnd, "Приложение GMENU\n(C) Фролов А.В., 1994", szWindowTitle, MB_OK | MB_ICONINFORMATION); return 0; } // Завершаем работу приложения case CM_FILEEXIT: { DestroyWindow(hwnd); return 0; } default: return 0; } } case WM_DESTROY: { // Уничтожаем созданные ранее меню DestroyMenu(hmenuFile); DestroyMenu(hmenuHelp); DestroyMenu(hmenuLineStyle); DestroyMenu(hmenu); // Удаляем изображения DeleteObject(hbmpLine1); DeleteObject(hbmpLine2); DeleteObject(hbmpLine3); DeleteObject(hbmpLine4); DeleteObject(hbmpLineStyle); DeleteObject(hbmpChecked); DeleteObject(hbmpUnchecked); PostQuitMessage(0); return 0; } default: break; } return DefWindowProc(hwnd, msg, wParam, lParam); } При обработке сообщения WM_CREATE приложение, наряду с другими инициализирующими действиями, загружает из ресурсов приложения все необходимые для меню изображения bitmap: hbmpLine1 = LoadBitmap(hInst, "LINE1"); hbmpLine2 = LoadBitmap(hInst, "LINE2"); hbmpLine3 = LoadBitmap(hInst, "LINE3"); hbmpLine4 = LoadBitmap(hInst, "LINE4"); hbmpLineStyle = LoadBitmap(hInst, "LINESTYLE"); hbmpChecked = LoadBitmap(hInst, "CHECKED"); hbmpUnchecked = LoadBitmap(hInst, "UNCHECKED"); Для строки "Demo Version" мы используем созданные нами и описанные в ресурсах приложения изображения bitmap, для чего вызываем функцию SetMenuItemBitmaps : SetMenuItemBitmaps(hmenuFile, CM_FILEDEMO, MF_BYCOMMAND, hbmpUnchecked, hbmpChecked); Далее мы отмечаем указанную строку: CheckMenuItem(hmenuFile, CM_FILEDEMO, MF_BYCOMMAND | MF_CHECKED); Затем мы переходим к формированию временного меню, содержащего графические изображения. Для этого в меню hmenuLineStyle, созданное ранее как пустое, мы добавляем четыре строки: AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP, CM_LINE1, (LPCSTR)(DWORD)hbmpLine1); AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP, CM_LINE2, (LPCSTR)(DWORD)hbmpLine2); AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP, CM_LINE3, (LPCSTR)(DWORD)hbmpLine3); AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP, CM_LINE4, (LPCSTR)(DWORD)hbmpLine4); Как видно из рис. 1.21, для строки "Line Style" используется нестандартный шрифт. Точнее говоря, для этой строки мы использовали изображение bitmap, на котором написаны слова "Line Style": AppendMenu(hmenu, MF_ENABLED | MF_POPUP | MF_BITMAP, (UINT)hmenuLineStyle, (LPCSTR)(DWORD)hbmpLineStyle); Перед завершением работы приложения мы удаляем все загруженные изображения bitmap для освобождения системных ресурсов: DeleteObject(hbmpLine1); DeleteObject(hbmpLine2); DeleteObject(hbmpLine3); DeleteObject(hbmpLine4); DeleteObject(hbmpLineStyle); DeleteObject(hbmpChecked); DeleteObject(hbmpUnchecked); Символические константы, использованные в приложении GMENU, описаны в файле gmenu.cpp (листинг 1.17). Листинг 1.17. Файл gmenu/gmenu.hpp #define CM_HELPABOUT 24346 #define CM_HELPUSING_HELP 24345 #define CM_HELPPROCEDURES 24344 #define CM_HELPCOMMANDS 24343 #define CM_HELPKEYBOARD 24342 #define CM_HELPINDEX 24341 #define CM_FILEEXIT 24338 #define CM_FILESAVEAS 24334 #define CM_FILESAVE 24333 #define CM_FILEOPEN 24332 #define CM_FILENEW 24331 #define CM_FILECLOSE 24330 #define CM_FILEDEMO 24329 #define CM_LINE1 100 #define CM_LINE2 101 #define CM_LINE3 102 #define CM_LINE4 103 Файл описания ресурсов приложения GMENU приведен в листинге 1.18. В нем находятся ссылки на изображения bitmap, используемые для отображения строк меню. Листинг 1.18. Файл gmenu/gmenu.rc LINE1 BITMAP "line1.bmp" LINE2 BITMAP "line2.bmp" LINE3 BITMAP "line3.bmp" LINE4 BITMAP "line4.bmp" CHECKED BITMAP "checked.bmp" UNCHECKED BITMAP "uncheck.bmp" LINESTYLE BITMAP "linestyl.bmp" В листинге 1.19 приведен внешний вид этих изображений. Листинг 1.19. Файлы gmenu/*.bmp
Файл определения модуля приложения GMENU приведен в листинге 1.20. Листинг 1.20. Файл gmenu/gmenu.def ; ============================= ; Файл определения модуля ; ============================= NAME GMENU DESCRIPTION 'Приложение GMENU, (C) 1994, Frolov A.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 8120 HEAPSIZE 1024 CODE preload moveable discardable DATA preload moveable multiple |