Глава 15
. Меню приложенияСамый простой и удобный способом создания меню приложения основан на использовании специального ресурса - шаблона меню. При создании приложения средствами
MFC AppWizard однооконное приложение по умолчанию будет иметь один ресурс меню, а многооконное - два.Для создания и изменения меню приложения следует использовать редактор ресурсов
Microsoft Developer Studio. Редактор ресурсов позволяет для каждой строки меню определить ее название, идентификатор, текст подсказки, а также некоторые дополнительные характеристики.Меню без явного создания объекта класса
CMe nuДля управления меню, как и для других элементов пользовательского интерфейса, в состав библиотеки
MFC включен специальный класс - класс CMenu . Класс CMenu является достаточно “незаметным” классом библиотеки MFC. Приложение может активно работать с меню, но все же в его исходных текстах можно не найти ни одного объекта этого класса.В приложениях, созданных с помощью
MFC AppWizard, меню создается автоматически вместе с панелью управления и панелью состояния. Для этого достаточно указать при создании шаблона документа общий идентификатор этих ресурсов, например :CMultiDocTemplate* pDocTemplate; // указатель на шаблон pDocTemplate = new CMultiDocTemplate // создание шаблона (IDR_MULTITYPE , RUNTIME_CLASS(CMultiDoc), RUNTIME_CLASS(CChildFrame), RUNTIME_CLASS(CMultiView)); AddDocTemplate(pDocTemplate); // добавить шаблон в список
В случае многооконного приложения дополнительно указываются ресурсы, используемые, когда все окна просмотра документов закрыты. Все эти ресурсы имеют один и тот же идентификатор, например
:CMainFrame* pMainFrame = new CMainFrame; // создание главного окна if (!pMainFrame->LoadFrame(IDR_MAINFRAME )) // загрузка ресурсов return FALSE; m_pMainWnd = pMainFrame; // соединение главного окна и объекта приложения
В приложениях
MFC AppWizard, имеющих однооконный или многооконный интерфейс, меню создается и изменяется самой библиотекой MFC. Несмотря на это, программист может сам управлять меню. Самым простым способом является обработка команд обновления от меню (см. ниже описание класса CCmdUI ).Если приложение создано без использования средств
AppWizard, то даже в этом случае процедура создания меню остается очень простой и также может не задействовать объекты класса CMenu напрямую.В таких приложениях обычно формируется главное окно на основе класса
CFrameWnd . Для этого сначала создается объект класса CFrameWnd , а затем вызывается либо метод Create , либо метод LoadFrame , который в свою очередь уже строит само окно вместе с меню.Метод
CreateЭто метод создает и инициализирует окно, связанное с объектом
CFrameWnd :BOOL Create( LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle = WS_OVERLAPPEDWINDOW, const RECT& rect = rectDefault, CWnd* pParentWnd = NULL, LPCTSTR lpszMenuName = NULL, DWORD dwExStyle = 0, CCreateContext* pContext = NULL );
Обязательно нужно указать только два первых параметра метода
Create - имя класса окна (если использовать NULL, то по умолчанию будет использоваться класс, определенный для окон CFrameWnd )и имя окна (его заголовок).Через параметр lpszMenuName можно задать имя ресурса меню, которое будет создано для данного окна. Например, вот как можно создать окно
c меню, шаблон которого определен в ресурсах и имеет идентификатор IDR_MENU (создание окна производится в конструкторе класса окон CMyFrame, наследуемого от CFrameWnd):CMyFrame::CMyFrame() { Create(NULL, "Окно с меню ",WS_OVERLAPPEDWINDOW, rectDefault,NULL,MAKEINTRESOURCE(IDR_MENU)); }
Метод
LoadFrameВиртуальный метод
LoadFrame позволяет динамически создавать меню, пользуясь информацией из файла ресурсов :virtual BOOL LoadFrame( UINT nIDResource, DWORD dwDefaultStyle= WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, CWnd* pParentWnd = NULL, CCreateContext* pContext=NULL);
Параметры этого метода почти идентичны параметрам метода
Create, описанного ранее. Исключение составляет параметр nIDResource. Он представляет собой идентификатор, общий для нескольких ресурсов, употребляемых при создании окна (меню, строковый ресурс заголовка окна, пиктограмма и таблица клавиш акселерации) :CMyFrame::CMyFrame() { LoadFrame(IDR_MENU); }
Создание объекта класса
CMenuМожно создать меню для окна и без использования методов
LoadFrame или Create класса CFrameWnd . Для этого необходимо создать объект класса CMenu и вызвать для него несколько методов.Объект класса
CMenu не является меню, он только представляет существующее меню типа HMENU. Можно создать объект класса как локальный, а после использования удалить (на меню как таковое это не повлияет).После объявления объекта класса
CMenu можно загрузить меню из ресурсов приложения при помощи метода LoadMenu . Этот метод загружает меню, заданное именем или идентификатором ресурса, и связывает его с соответствующим объектом класса CMenu .После того, как меню “загружено”, его можно подключить к окну, воспользовавшись методом
SetMenu , входящим в класс CWnd . Если необходимо просто удалить текущее меню, используемое окном, то методу SetMenu следует передать значение NULL.После установки меню методом
SetMenu и до того, как соответствующий объект CMenu будет удален, необходимо вызвать метод Detach класса CMenu . Этот разорвет связь между меню и соответствующим объектом класса CMenu, после чего последний может быть удален .Следует отметить, что если до установки нового меню окно уже имело меню, надо удалить его, воспользовавшись методом
DestroyMenu класса CМ enu .Если с меню, подлежащим удалению, не связан объект класса
CMenu , можно обратиться к методу Attach класса CMenu , который устанавливает связь между меню типа и объектом класса CMenu.Для определения идентификатора меню типа
известного окна можно воспользоваться методом GetMenu класса CWnd. Этот метод возвращает указатель на объект типа CMenu . Теперь для получения идентификатора меню можно обратиться к элементу данных m_hMenu, входящему в класс CMenu.Рассмотрим фрагмент программы (в реализации класса
CMyFrame, наследуемого от CFrameWnd), в котором происходит замена старого меню на новое :void CMyFrame::OnChangeMenu() { // удаление старого меню // получаем указатель на текущее меню окна CMenu *pMenu=this->GetMenu(); // связываем меню HMENU с объектом menuCurrent CMenu menuCurrent.Attach(pMenu->m_hMenu); // удаляем меню и все связанные с ним ресурсы процесса menuCurrent.DestroyMenu(); // установление нового меню // загружаем меню IDR_MENU CMenu menuNew=LoadMenu(IDR_MENU); // устанавливаем загруженное меню this->SetMenu(&menuNew); // разрываем связь меню с объектом menuNew menuNew.Detach(); }
Класс
CMenu помимо методов создания меню содержит и методы управления меню. Используя эти методы, можно добавлять к меню новые строки, изменять и удалять их. Специальные методы класса CMenu позволяют выделять некоторые строки меню и создавать элементы меню, содержащие не только текст, но и изображение.При выборе пользователем пункта меню окну приходит соответствующее сообщение. Для его обработки следует предусмотреть специальные методы класса окна, при этом в таблицу сообщения класса окна необходимо добавить соответствующие макрокоманды типа
ON_COMMAND.