2. Запрограммировать метод обработки сообщения, добавляющий (и удаляющий) в созданное меню динамический элемент меню (например, имя файла).
Предположим, что при активизации дочернего окна MDI-приложения к некоторому раскрывающемуся меню будет добавлено три динамических элемента меню. Первое, что следует сделать, - это определить в редакторе меню идентификаторы ресурса для этих элементов меню. Далее с помощью ClassWizard следует вставить для класса дочернего окна-рамки (например, CChildFrame1) метод обработки сообщения WM_MDIACTTVATE.
Приведем сокращенный текст кода метода обработки сообщения WM_MDIACTIVATE, добавляющий динамический элемент меню.
void CCaildFrame::OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd* pDeactivateWnd) { if (bActivate) // Окно активно CMenu *pMenu=AfxGetMainWnd()->GetMenu(); // Указатель на меню int iNum; UNIT uID; for (iNum = pMenu->GetMenuItemCount()-l; iNum>=0; iNum—) { CMenu* pSumMenu= pMenu->GetSubMenu(iNum); // Указатель на подменю if (pSubMenu && pSubMenu->GetMenuItemID() == ID_Last // ID_Last идентификатор элемента меню, предшествующего // добавляемому динамическому элементу меню pMenu=pSubMenu; uID=IDJLast+l; } // sStr - заголовок динамического элемена меню pMenu->AppendMenu(MF STRING || MF ENABLED, uID, sStr); ■ |
Класс CMenu
Класс CMenu инкапсулирует функционирование Windows-меню HMENU в объекте данного класса. Он поддерживает создание, управление, изменение и разрушение меню.
Для создания и использования нового меню в некотором окне можно:
• создать объект CMenu;
• вызвать метод CWnd::SetMenu для назначения меню данному окну (после отключения предыдущего меню, если оно было, вызовом метода Detach);
Метод CWnd::SetMenu устанавливает для окна новое меню, инициирует | перерисовку меню окна и передает объект меню "в собственность" окне. Метод Detach отсоединяет HMENU от объектГ CMenu, не выполняя при этом разрушения меню. Меню само автоматически разрушается при разру- I шении окна, владеющего этим меню.
Меню также может быть создано из шаблона, расположенного в памяти J вызовом метода LoadMenuIndirect.
Самым простым способом, однако, является создание меню на основе шаблона ресурса меню, созданного средствами редактора меню. Для его использования достаточно вызвать метод LoadMenu, выполняющий загрузку ресурса меню.
Элемент меню может указываться по идентификатору команды, если он есть, или по позиции. Позиция первого элемента равна нулю.
Отметим, что при определении элемента меню по позиции всегда используется текущий объект CMenu:
• если CMenu является линейкой меню (меню верхнего уровня), то это позиция элемента в линейке меню;
• если Степи - это подменю или вложенное меню, то позиция указывает соответственно на элемент подменю или вложенного меню.
Члены класса cMenu: :m_hMenu
Определяет дескриптор HMENU Windows-меню, пристыкованного к объекту CMenu.
CMenu();
Конструктор объекта CMenu.
Для того чтобы создать меню после выполнения конструктора, необходимо вызвать один из следующих методов, выполняющих создание или загрузку меню:
• GreateMenu,
• CreatePopupMenu,
• LoadMenu,
• LoadMenuIndirect,
• Attach.
BOOL CreateMenu ( );
Создает Windows-меню и пристыковывает его к объекту CMenu.
Создаваемое меню первоначально пусто. Для добавления элементов меню можно использовать методы AppendMenu или InsertMenu.
Если меню подчинено окну, то оно автоматически разрушается при раз- j рушении окна. В противном случае приложение предварительно перед своим завершением должно освободить системные ресурсы, ассоциируемые с меню, вызвав метод DestroyMenu.
BOOL CreatePopupMenu ();
Метод создает пустое подменю (ниспадающее меню) и пристыковывает его к объекту CMenu.
Подменю может быть добавлено к существующему меню или подменю.
Метод TrackPopupMenu позволяет отображать подменю как плавающее . меню.
BOOL LoadMenu (LPCTSTR lpszResourceName); BOOL LoadMenu (UINT nIDResource);
Метод загружает ресурс меню из выполнимого файла приложения и пристыковывает его к объекту CMenu. Параметры:
lpszResourceName - указатель на строку, содержащую имя ресурса меню.
nIDResource - ID ресурса меню.
BOOL LoadMenuIndirect (const void* lpMenuTemplate);
Метод загружает меню из шаблона меню из памяти и пристыковывает его к объекту CMenu. Параметры:
lpMenuTemplate - указатель на шаблон меню (это структура MENUITEMTEMPLATEHEADER и набор из одной или более структур MENUITEMTEMPLATE).
BOOL Attach (HMENU hMenu);
Метод пристыковывает существующее Windows-меню к объекту CMenu. После этого с меню можно работать, как с объектом класса CMenu.
Если пристыковываемое Windows-меню уже ассоциировано с каким-либо окном, то для получения указателя можно использовать метод CWnd::GetMenu.
Пример:
CMenu mnu; \ HMENU hmnu = pWnd->GetMenu(); i mnu.Attach( hmnu); |
static CMenu* PASCAL FromHandle (HMENU hMenu);
Метод возвращает указатель на объект CMenu для заданного Windows-меню.
Если Windows-меню не сопоставлен никакой объект CMenu, то метод возвращает указатель на временно созданный и пристыкованный объект.
HMENU GetSafeHmenu ( ) const;
Метод возвращает HMENU для объекта CMenu. BOOL DestroyMenu ( );
Метод разрушает меню и освобождает все используемые им ресурсы Windows. При этом меню отстыковывается от объекта CMenu. Этот метод автоматически вызывается из деструктора.
BOOL DeleteMenu (UINT nPosition, UINT nFlags);
Метод удаляет из меню указанный элемент. Если удаляемый элемент имеет ассоциируемое с ним подменю, то метод разрушает указатель на подменю и освобождает используемую им память.
Параметры:
nPosition - определяет удаляемый элемент меню в соответствии со значением nFlags.
nFlags - определяет, как следует интерпретировать параметр nPosition и может принимать следующие значения:
MF_BYCOMMAND - параметр nPosition указывает Ш команды существующего пункта меню;
MF_BYPOSITION - параметр nPosition указывает позицию существующего пункта меню. Позиция первого элемента меню равна нулю.
При изменении меню, расположенного в окне, приложение должно вызвать метод CWnd::DrawMenuBar.
BOOL TrackPopupMenu (UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT ipRect = NULL);
Метод отображает плавающее подменю в указанной позиции и самостоятельно отслеживает выбор пункта меню. Плавающее меню может быть отображено в любом месте экрана. Такое меню также называется контекстным меню.
Параметры:
nFlags - параметр определяет позицию экрана и кнопку мыши и может быть задан следующими флажками:
• для указания позиции выравнивания по горизонтали относительно х-ко-ординаты: TPM_CENTERALIGN, TPMJLEFTALIGN, TPM_RIGHTALIGN;
• для определения кнопки мыши, выполняющей выбор пункта меню: TPM_LEFTBUTTON, TPM_RIGHTBUTTON.
х - позиция подменю по горизонтали в экранных координатах. у - позиция верхней точки подменю по вертикали в экранных координатах. pWnd - указатель окна, владеющего подменю. Это окно получает от меню сообщение WMCOMMAND после завершения TrackPopupMenu.
IpRect - указатель на структуру RECT, содержащую экранные координаты прямоугольной области, при щелчке пользователя внутри которой не происходит удаления подменю. Если значение этого параметра равно NULL, то такая прямоугольная область ограничивается рамкой меню.
BOOL AppendMenu (UINT nFlags, UINT nIDNewItem = 0, LPCTSTR
ipszNewItem = NULL);
BOOL AppendMenu (UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp);
Метод добавляет новый элемент в конец меню.
При любом изменении элементов меню приложение должно вызывать метод CWnd::DrawMenuBar.
Параметры:
nFlags - определяет состояние добавляемого элемента меню и может быть указан комбинацией следующих флажков:
MF_CHECKED - переключаемый элемент: состояние включен (V);
MF_UNCHECKED - переключаемый элемент: состояние выключен;
MF_DISABLED - элемент недоступен для выбора;
MF_ENABLED - элемент доступен;
MF_GRAYED - элемент недоступен для выбора и отображается "посеревшим";
MFJMENUBARBREAK - элемент линейки меню размещается на новой строке, а элемент подменю - в новом столбце, отделенном вертикальной линией;
MF_MENUBREAK - элемент линейки меню размещается на новой строке, а элемент подменю - в новом столбце, но без разделительной линии между столбцами;
MF_OWNERDRAW - самоотображаемый элемент меню (не используется для элементов линейки меню). При первом отображении элемента меню окно, владеющее меню, получает сообщение WM_MEASUREITEM для определения ширины и высоты элемента меню. Для обновления отображения элемента меню владельцу меню посылается сообщение WM_DRAWITEM;
MF_POPUP - элемент меню имеет ассоциированное с ним подменю, дескриптор которого задается параметром ID. Используется для добавления или подменю верхнего уровня (для линейки меню) или построения иерархических подменю;
MF_SEPARATOR - отображение горизонтальной разделительной линии (только для подменю);
MF_STRING - элемент меню является строкой текста.
nIDNewItem - в зависимости от значения параметра nFlags определяет или
ID команды нового элемента меню, или указатель (HMENU) Подменю (nFlags= MFPOPUP). Параметр игнорируется для nFlags, равного I
MF_SEPARATOR.
ipszNewItem - определяет содержание нового элемента меню. В зависимости от ;
значения nFlags этот параметр может иметь различную интерпретацию:
MF_OWNERDRAW - содержит 32-битовое значение, используемое приложением для дополнительной информации, ассоциируемой с элементом меню. Это 32-битовое значение доступно при обработке сообщений WM_MEASUREITEM и WM_DRAWITEM (значение содержится в члене itemData структуры, используемой этими сообщениями);
MF_STRING - содержит указатель на строку (используется по умолчанию); ]
MF_SEPARATOR - параметр IpszNewItem игнорируется.
рВтр - указатель на объект CBitmap, который будет использоваться как \
элемент меню.
BOOL InsertMenu ( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0, LPCTSTR IpszNewItem = NULL );
BOOL InsertMenu ( UINT nPosition, UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp);
Метод вставляет новый элемент меню в указанную параметром nPosition позицию.
Когда nIDNewItem определяет подменю, то он становится частью меню, в которое вставляется. При разрушении меню вставленное меню также будет разрушено. Для избежания конфликтов вставленное меню должно быть отстыковано от объекта CMenu.
Отметим, что если в MDI-приложении дочернее окно документа распахнуто до полноэкранного состояния (максимизировано) и приложение выполняет вставку подменю, используя флажок MF_BYPOSITION (по позиции), то реально будет выполнена вставка на один элемент левее ожидаемого результата. Это происходит в связи с тем, что линейка меню для полноэкранного состояния дочернего окна дополняется слева его системным меню Control. При нормальном состоянии системное меню Control располагается в левом верхнем углу дочернего окна документа. UINT CheckMenuItem ( UINT nIDCheckltem, UINT nCheck );
Метод устанавливает или снимает для переключаемого элемента меню состояние включен/выключен (V).
При успешном завершении метод возвращает значение предыдущего состояния элемента: MF_CHECKED или MF_UNCHECKED, а если элемент не существует, то значение OxFFFFFFFF.
Параметры:
nIDCheckltem - указывает элемент меню по идентификатору (иCheck = MF_BYCOMMAND) или по порядковому номеру - позиции (nCheck — MF_BYPOSITION).
nCheck - определяет, как указывается элемент меню и устанавливаемое состояние. Параметр может быть задан комбинацией флажков MF_CHECKED или MFJJNCHECKED с флажками MF_BYPOSITION или MF_BYCOMMAND.
Отметим, что переключаемым элементом может быть как элемент подменю, так и элемент меню (но не элемент линейки меню). Элемент подменю может быть указан только по позиции, так как не имеет идентификатора элемента меню, ассоциированного с ним.
BOOL CheckMenuRadioItem ( UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags);
Метод помечает указанный элемент меню из группы элементов (•) и снимает пометку с другого элемента группы. При отображении группы элементов меню, только один из которых может быть помечен, пометка отображается в виде или буллета, или битового изображения радиокнопки.
Параметры:
nIDFirst, nIDLast - определяют первый и последний элементы меню группы элементов.
nIDItem - определяет помечаемый элемент меню.
nFlags - указывает как интерпретируются значения параметров: при значении, равном MF_BYCOMMAND, используется ID существующих элементов меню (значение по умолчанию), при значении MFBYPOSITION, параметры указывают позицию элементов меню.
UINT EnableMenuItem( UINT nIDEnableltem, UINT nEnable );
Метод устанавливает для указанного элемента меню одно из следующих состояний: MF_DISABLED, MF_ENABLED, MF_GRAYED.
При успешном завершении метод возвращает предыдущее состояние, в противном случае - значение -1.
Параметр nEnable также указывает, как задан элемент меню: по идентификатору (MF_BYCOMMAND) или по no3HUHH(MF_BYPOSiTION). UINT GetMenuItemCount ( ) const;
При успешном завершении метод возвращает количество элементов данного меню (линейки меню или подменю), и -1 - в противном случае.
UINT GetMenuItemID ( int nPos ) const;
При успешном завершении метод возвращает идентификатор ID ука- J занного по позиции элемента подменю; если указано само подменю, то I значение -1; если указан элемент-разделитель, то значение 0. UINT GetMenuState ( UINT nID, UINT nFlags ) const;
Метод возвращает состояние элемента меню или количество элементов ;j в подменю.
Параметр nld может указываться или по позиции, или по идентифика-тору команды, в зависимости от значения nFlags.
Если указанный элемент не существует, то метод возвращает значение | OxFFFFFFFF. Если nld указывает подменю, то старший байт содержит ко- | личество элементов в подменю, а младший - флажки, ассоциируемые с | этим подменю. В противном случае (для элемента меню) возвращаемое значение является маской значений флажков, начинающихся с префикса , MF_. Маска описывает состояние элемента меню, комбинируя допустимые значения (оператор ИЛИ).
int GetMenuString( UINT nIDItem, LPTSTR ipString, int nMaxCount, UINT nFlags) const; int GetMenuString( UINT nIDItem, CString& rString, UINT nFlags ) const;
Метод определяет надпись для указанного элемента меню и возвращает I число байт, скопированных в указанный буфер (не включая 0-символ).
Параметр nIDItem может указываться или по позиции, или по идентификатору команды, в зависимости от значения nFlags.
Параметр nMaxCount должен быть на единицу больше, чем длина над- < писи (не включая 0-символ). CMenu* GetSubMenu (int nPos ) const;
Метод возвращает указатель на объект CMenu, определяющий по значе- ; нию m_hMenu подменю, или NULL.
BOOL ModifyMenu ( UINT nPosition, UINT nFlags, UINT nlDNewItem = 0, LPCTSTR ipszNewItem = NULL );
BOOL ModifyMenu ( UINT nPosition, UINT nFlags, UINT nlDNewItem, const CBitmap* pBmp );
Эти методы позволяют модифицировать существующие элементы меню. BOOL RemoveMenu ( UINT nPosition, UINT nFlags );
Метод удаляет из меню указанный элемент меню (и ассоциированное с ним подменю).
Для того чтобы повторно использовать удаляемое меню, можно перед I вызовом этого метода вызвать метод GetSubMenu для получения подменю CMenu.
Для удаления меню и одновременного освобождения ресурсов следует использовать метод DeleteMenu.
BOOL SetMenuItemBitmaps (UINT nPosition, UINT nFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked);
Метод ассоциирует с указанным элементом меню заданное битовое изображение, отображаемое, когда элемент меню имеет состояние включен/выключен.
Если один из параметров pBmpUnchecked или pBmpChecked равен NULL, то Windows ничего не отображает для пометки элемента меню, но если оба параметра одновременно равны NULL, то используется стандартный символ пометки V.
При разрушении меню приложение само должно удалить объекты CBitmap.
Для получения размера стандартного символа пометки следует использовать метод GetMenuCheckMarkDimensions.
BOOL SetMenuContextHelpId (DWORD dwContextHelpl );
Метод позволяет установить идентификатор ID контекста справки, ассоциированной с CMenu. Это идентификатор разделяется всеми элементами меню: нельзя установить свой ID контекста для отдельного элемента меню.
Параметры:
dwContextHelpId - ID контекста справки, ассоциированной с CMenu. DWORD GetMenuContextHelpId ( ) const;
Метод возвращает идентификатор ID контекста справки, ассоциированной с CMenu, или 0 в противном случае.
virtual void Drawltem (LPDRAWITEMSTRUCT ipDrawItemStmci);
Метод вызывается средой выполнения при изменении меню, для которого установлен флажок самоотображения. Информация для отрисовки элемента меню передается в структуре DRAWITEMSTRUCT.
При этом приложение до завершения выполнения этого метода должно восстановить графический контекст устройства.
Структура DRAWITEMSTRUCT имеет следующее описание:
typedef struct tagDRAWITEMSTRUCT {
UINT CtlType; // Тип элемента управления UINT CtllD; // ID элемента управления
//(не используется для меню) UINT itemID; UINT itemAction; UINT ; itemState; HWND ■ hwndltem;
HDC hDC; RECT rcltera; DWORD itemData; } DRAWITEMSTRUCT;
Самоотображаемое окно или самоотображаемый элемент управления или меню получают в lParam указатель на эту структуру при обработке сообщения WM_DRAWITEM.
Член CtlType определяет тип элемента управления и может быть задан следующими флажками: ODT_BUTTON, ODT_COMBOBOX, ODTJLISTBOX, ODT_MENU, ODTJiSTVIEW, ODT_STATIC, ODT_TAB. CtllD - ID списка, комбинированного списка или кнопки. Для меню не используется.
itemID - ID элемента меню или индекс элемента в списке или комбинированном списке.
itemAction - определяет, в каких случаях выполнять перерисовку: ODA_DRAWENTIRE - необходима перерисовка; ODA_FOCUS - перерисовка при получении или потере фокуса; ODA_SELECT - перерисовка при изменении состояния выделенное™. itemState - определяет визуальное состояние элемента после выполнения перерисовки и указывается следующими флажками: ODS_CHECKED, ODS_DISABLED, ODS_FOCUS, ODS_GRAYED, ODS_SELECTED, ODS_COMBOBOXEDIT, ODS_DEFAULT.
hwndltem - указатель окна элемента управления или HMENU меню, содержащего элемент меню. hDC - контекст устройства.
rcltem - прямоугольная область для контекста устройства, определяемого членом hDC.
itemData - для элементов управления список может содержать значение, передаваемое методами CComboBox::AddString, CComboBox::InsertString, CListBox::AddString, CListBox::InsertString; для меню - значение, передаваемое методами CMenu::AppendMenu, CMenu::InsertMenu или CMenu:: ModifyMenu.