Приложение MultiMenu
Создайте новый проект под названием MultiMenu. В качестве типа приложения выберите из списка Type строку Application. Настройте проект MultiMenu, указав что приложение будет работать с библиотекой классов MFC.
Наберите в редакторе исходный текст приложения и сохраните его в файле MultiMenu.cpp (листинг 3.1). Включите готовый файл MultiMenu.cpp в проект.
Листинг 3.1. Файл MultiMenu.cpp
//============================================================
// Приложение MultiMenu
// (c) Frolov G.V., 1996
// E-mail: frolov@glas.apc.org
//============================================================
// Включаемые файлы для MFC
#include <afxwin.h>
#include <afxext.h>
#include <afxcmn.h>
// Включаемый файл для ресурсов приложения и идентификаторов
#include "resource.h"
//============================================================
// Класс CMultiMenuApp - главный класс приложения
//============================================================
class CMultiMenuApp : public CWinApp
{
public:
// Мы будем переопределять метод InitInstance,
// предназначенный для инициализации приложения
virtual BOOL InitInstance();
};
// Создаем объект приложение класса CMultiMenuApp
CMultiMenuApp MultiMenuApp;
//============================================================
// Класс CMultiMenuWindow - представляет главное окно
//============================================================
class CMultiMenuWindow : public CFrameWnd
{
protected:
// Панель состояния
CStatusBar m_wndStatusBar;
// Флаг управляет строкой Prosess меню Mission
BOOL bEnable;
// Флаг управляет строкой Construction меню Mission
BOOL bRadio;
// Флаг управляет строкой Restrict меню Menu
int nCheck;
protected:
// Метод для создания окна приложения и панели состояния
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
// Методы для обработки командных сообщений
// от меню приложения
afx_msg void CMultiMenuWindow::OnDisable();
afx_msg void CMultiMenuWindow::OnCommand();
afx_msg void CMultiMenuWindow::OnExit();
afx_msg void CMultiMenuWindow::OnConstruct();
afx_msg void CMultiMenuWindow::OnRestrictMenu();
afx_msg void CMultiMenuWindow::OnFullMenu();
// Методы для обновления меню
afx_msg void OnUpdateProcess(CCmdUI* pCmdUI);
afx_msg void OnUpdateConstruct(CCmdUI* pCmdUI);
afx_msg void OnUpdateDisable(CCmdUI* pCmdUI);
public:
// Конструктор класса CMultiMenuWindow
CMultiMenuWindow();
// Макрокоманда необходима, так как класс
// CMultiMenuWindow обрабатывает сообщения
DECLARE_MESSAGE_MAP()
};
//============================================================
// Таблица сообщений класса CMultiMenuWindow
//============================================================
BEGIN_MESSAGE_MAP(CMultiMenuWindow, CFrameWnd)
// Макрокоманда вызывает метод OnCreate
ON_WM_CREATE()
// Макрокоманда вызывает метод OnContextMenu
ON_WM_CONTEXTMENU()
// Макрокоманды для обработки командных сообщений
ON_COMMAND(ID_MENU_DISABLE, OnDisable)
ON_COMMAND(ID_MISSION_CONSTRUCT, OnConstruct)
ON_COMMAND(ID_FILE_EXIT, OnExit)
ON_COMMAND(ID_MISSION_PROCESS, OnCommand)
ON_COMMAND(ID_MENU_RESTRICT, OnRestrictMenu)
ON_COMMAND(ID_MENU_FULL, OnFullMenu)
// Обработчики сообщений ON_UPDATE_COMMAND_UI
ON_UPDATE_COMMAND_UI(ID_MISSION_PROCESS, OnUpdateProcess)
ON_UPDATE_COMMAND_UI(ID_MISSION_CONSTRUCT,
OnUpdateConstruct)
ON_UPDATE_COMMAND_UI(ID_MENU_DISABLE, OnUpdateDisable)
END_MESSAGE_MAP()
// Индикатор панели управления
UINT indicator = ID_SEPARATOR;
//============================================================
// Метод InitInstance класса CMultiMenuApp
// Создает главное окно приложения и отображает его на экране
//============================================================
BOOL CMultiMenuApp::InitInstance()
{
m_pMainWnd = new CMultiMenuWindow();
m_pMainWnd -> ShowWindow(m_nCmdShow);
m_pMainWnd -> UpdateWindow();
return TRUE;
}
//============================================================
// Конструктор класса CMultiMenuWindow
//============================================================
CMultiMenuWindow::CMultiMenuWindow()
{
// Создаем окно приложения, соответствующее
// данному объекту класса CMultiMenuWindow
Create(NULL, "Multi Menu Sample", WS_OVERLAPPEDWINDOW,
rectDefault, NULL, MAKEINTRESOURCE(IDR_FULL_MENU));
// Загружаем таблицу клавиш акселерации
LoadAccelTable(MAKEINTRESOURCE(IDR_ACCELERATOR));
// Инициализируем флаги
bEnable = TRUE;
bRadio = TRUE;
nCheck = 0;
}
//============================================================
// Метод OnCreate класса CMultiMenuWindow
// Вызывается во время создания окна приложения
//============================================================
int CMultiMenuWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// Вызываем метод OnCreate базового класса
if(CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// Создаем панель состояния
if(!m_wndStatusBar.Create(this))
{
// Ошибка при создании панели состояния
TRACE0("Failed to create status bar\n");
return -1;
}
// Отображаем индикаторы панели состояния
if(!m_wndStatusBar.SetIndicators(&indicator,1))
{
// Ошибка при установке индикатора
TRACE0("Failed to set indicators\n");
return -1;
}
return 0;
}
//============================================================
// Метод OnDisable класса CMultiMenuWindow
// Изменяем состояние флагов bEnable и nCheck
//============================================================
void CMultiMenuWindow::OnDisable()
{
// Меняем значение bEnable с TRUE на FALSE и наоборот
bEnable = !bEnable;
// Меняем значение bEnable с 1 на 0 и наоборот
nCheck = (nCheck == 1) ? 0 : 1;
}
//============================================================
// Метод OnRestrictMenu класса CMultiMenuWindow
// Изменяем меню приложения с IDR_FULL_MENU на
// IDR_RESTRICT_MENU
//============================================================
void CMultiMenuWindow::OnRestrictMenu()
{
CMenu menuOld; // текущее меню
CMenu menuRestrict; // новое меню
CMenu* pMenu;
// Получаем указатель на текущее меню
pMenu = this->GetMenu();
// Связываем меню с объектом menuOld
menuOld.Attach(pMenu->m_hMenu);
// Удаляем меню
menuOld.DestroyMenu();
// Загружаем меню IDR_RESTRICT_MENU
menuRestrict.LoadMenu(IDR_RESTRICT_MENU);
// Устанавливаем загруженное меню
SetMenu(&menuRestrict);
// Разрываем связь меню с объектом menuRestrict
menuRestrict.Detach();
}
//============================================================
// Метод OnFullMenu класса CMultiMenuWindow
// Изменяем меню приложения с IDR_RESTRICT_MENU на
// IDR_FULL_MENU
//============================================================
void CMultiMenuWindow::OnFullMenu()
{
CMenu menuOld;
CMenu menuRestrict;
CMenu* pMenu;
pMenu = this->GetMenu();
menuOld.Attach(pMenu->m_hMenu);
menuOld.DestroyMenu();
menuRestrict.LoadMenu(IDR_FULL_MENU);
SetMenu(&menuRestrict);
menuRestrict.Detach();
}
//============================================================
// Метод OnCommand класса CMultiMenuWindow
//============================================================
void CMultiMenuWindow::OnCommand()
{
MessageBox("Command not implemented");
}
//============================================================
// Метод OnConstruct класса CMultiMenuWindow
// Изменяем состояние флага bRadio
//============================================================
void CMultiMenuWindow::OnConstruct()
{
// Меняем значение bRadio с TRUE на FALSE и наоборот
bRadio = !bRadio;
}
//============================================================
// Метод OnExit класса CMultiMenuWindow
//============================================================
void CMultiMenuWindow::OnExit()
{
// Завершаем приложение
DestroyWindow();
return;
}
//============================================================
// Метод OnUpdateProcess класса CMultiMenuWindow
//============================================================
void CMultiMenuWindow::OnUpdateProcess(CCmdUI* pCmdUI)
{
// Блокируем или разблокируем строку Process меню Mission
pCmdUI->Enable(bEnable);
}
//============================================================
// Метод OnUpdateConstruct класса CMultiMenuWindow
//============================================================
void CMultiMenuWindow::OnUpdateConstruct(CCmdUI* pCmdUI)
{
// Устанавливаем или снимаем пометку
// строки Construction меню Mission
pCmdUI->SetRadio(bRadio);
}
//============================================================
// Метод OnUpdateDisable класса CMultiMenuWindow
//============================================================
void CMultiMenuWindow::OnUpdateDisable(CCmdUI* pCmdUI)
{
// Устанавливаем или удаляем пометку
// у строки Disable меню Menu
pCmdUI->SetCheck(nCheck);
}
Создайте новый файл ресурсов и включите его в проект под именем MultiMenu.rc. Включите в него два меню, присвоив им идентификаторы IDR_RESTRICT_MENU и IDR_FULL_MENU.
Введите строки этих меню в соответствии с представленным нами файлом ресурсов (листинг 3.2). Для всех строк меню введите их описания. Они будут записаны в файл ресурсов как строковые ресурсы, имеющие одинаковые идентификаторы со строками меню.
Добавьте в файл ресурсов строку Ready, выбрав для нее идентификатор AFX_IDS_IDLEMESSAGE. Эта строка будет отображаться в панели состояния во время “бездействия” приложения.
Включите в файл ресурсов таблицу акселераторов, состоящую из трех команд: ID_MENU_DISABLE, ID_MISSION_PROCESS и ID_FILE_EXIT. Присвойте им комбинации клавиш <Ctrl+D>, <Ctrl+P> и <Ctrl+E> соответственно.
Листинг 3.2. Файл MultiMenu.rc
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
//////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
//////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
//////////////////////////////////////////////////////////////
// Russian resources
#if !defined(AFX_RESOURCE_DLL) defined(AFX_TARG_RUS)
#ifdef _WIN32
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
#pragma code_page(1251)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////
//
// Menu
//
IDR_RESTRICT_MENU MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "P&rocess\tCtrl+P", ID_MISSION_PROCESS
MENUITEM SEPARATOR
MENUITEM "E&xit\tCtrl+E", ID_FILE_EXIT
END
POPUP "&Menu"
BEGIN
MENUITEM "Full", ID_MENU_FULL
MENUITEM "Disa&ble\tCtrl+D", ID_MENU_DISABLE
END
POPUP "&Help", HELP
BEGIN
MENUITEM "Help index", ID_HELP_HELPINDEX
MENUITEM SEPARATOR
MENUITEM "System info", ID_HELP_SYSTEMINFO
END
END
IDR_FULL_MENU MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM SEPARATOR
MENUITEM "E&xit\tCtrl+E", ID_FILE_EXIT
END
POPUP "&Menu"
BEGIN
MENUITEM "Restrict", ID_MENU_RESTRICT
MENUITEM "Disa&ble\tCtrl+D", ID_MENU_DISABLE
END
POPUP "M&ission"
BEGIN
MENUITEM "P&rocess\tCtrl+P", ID_MISSION_PROCESS
MENUITEM SEPARATOR
MENUITEM "Construction", ID_MISSION_CONSTRUCT
END
POPUP "&Help", HELP
BEGIN
MENUITEM "Help index", ID_HELP_HELPINDEX
MENUITEM "Context help", ID_HELP_CONTEXTHELP
MENUITEM SEPARATOR
MENUITEM "System info", ID_HELP_SYSTEMINFO
END
END
//////////////////////////////////////////////////////////////
//
// Accelerator
//
IDR_ACCELERATOR ACCELERATORS DISCARDABLE
BEGIN
"D", ID_MENU_DISABLE, VIRTKEY, CONTROL, NOINVERT
"E", ID_FILE_EXIT, VIRTKEY, CONTROL, NOINVERT
"P", ID_MISSION_PROCESS, VIRTKEY, CONTROL, NOINVERT
END
//////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
AFX_IDS_IDLEMESSAGE "Ready"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_FILE_EXIT "Exit application"
ID_MISSION_PROCESS "Process"
ID_HELP_HELPINDEX "Open help index"
ID_HELP_CONTEXTHELP "Context help"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_HELP_SYSTEMINFO "Display system info"
ID_MISSION_CONSTRUCT "Construct"
ID_MENU_RESTRICT "Restrict menu"
ID_MENU_FULL "Display full menu"
ID_MENU_DISABLE " Disable command Process from menu Mission"
END
#endif // Russian resources
//////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
//////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
Идентификаторы ресурсов приложения MultiMenu определены в файле resource.h. Этот файл создается автоматически редактором ресурсов Microsoft Visual C++. Исходный текст этого файла представлен в листинге 3.3.
Листинг 3.3. Файл resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by MultiMenu.rc
//
#define IDR_RESTRICT_MENU 106
#define IDR_FULL_MENU 107
#define IDR_ACCELERATOR 108
#define ID_FILE_EXIT 40009
#define ID_MISSION_PROCESS 40013
#define ID_HELP_HELPINDEX 40014
#define ID_HELP_CONTEXTHELP 40015
#define ID_HELP_SYSTEMINFO 40016
#define ID_MISSION_CONSTRUCT 40017
#define ID_MENU_RESTRICT 40019
#define ID_MENU_FULL 40020
#define ID_MENU_DISABLE 40025
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 110
#define _APS_NEXT_COMMAND_VALUE 40027
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
Постройте приложение MultiMenu и запустите его. На экране появится окно приложения с главным меню и панелью состояния (рис. 3.4).
В панели состояния расположен один индикатор. В нем отображается подсказка о выбранной строке меню приложения или системного меню, а если приложение “бездействует” - строка Ready.
Рис. 3.4. Приложение MultiMenu
Сразу после запуска приложения MultiMenu используется меню с идентификатором IDR_FULL_MENU. Если вы выберите из меню Menu строку Restrict, то меню приложения будет заменено на меню IDR_RESTRICT_MENU. Это сокращенный вариант меню IDR_FULL_MENU, в котором отсутствуют некоторые строки, а строка Process перенесена из меню Mission в меню File.
Различные строки меню IDR_FULL_MENU и IDR_RESTRICT_MENU иллюстрируют режимы отображения строк меню. Так, при выборе из меню Menu строки Disable, блокируется строка Process в меню Mission. Около строки Disable при этом отображается символ Ö (рис. 3.3). Чтобы снять блокировку, выберите строку Disable из меню Menu еще раз. Символ Ö также исчезнет.
При выборе строки Process из меню Mission на экране появляется сообщение. Когда строка Process заблокирована, выбрать ее невозможно.
Если вы выберите из меню Mission строку Construction, то она будет выделена символом ·. Повторный выбор этой строки снимает с нее выделение.
Чтобы завершить работу приложения MultiMenu, можно выбрать из меню File строку Exit или выбрать из системного меню приложения строку Close. Все остальные строки меню приложения не работают и заблокированы.
Для ускорения выбора некоторых команд из меню приложения можно воспользоваться клавишами акселерации. В программе определены три такие комбинации.
Комбинация клавиш |
Соответствующая строка меню |
<Ctrl+D> |
Строка Disable из меню Menu |
<Ctrl+P> |
Строка Process из меню Mission или из меню File (для сокращенного варианта меню) |
<Ctrl+E> |
Строка Exit из меню File |