Операционная система 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 |

