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

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


linestyl.bmp
line2.bmp
line3.bmp
line3.bmp
line4.bmp
checked.bmp
uncheck.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

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