VC. Меню и акселераторы |
||||||
---|---|---|---|---|---|---|
В этой статье я вас ознакомлю с классом CMenu.
С помощью этого класса можно создавать меню в MFC приложениях. Так же будет
рассмотрен вопрос об использовании акселераторов. Итак, начнем с описания класса
CMenu. Класс CMenu Рассмотрим некоторые наиболее важные функции и переменные этого класса. ° m_hMenu ? дескриптор меню, связанный с объектом класса CMenu. ° BOOL CreateMenu() ? создает пустое меню и связывает его с объектом класса CMenu. ° BOOL CreatePopupMenu() ? создает пустое выпадающее меню и соединяет с объектом класса CMenu. ° BOOL LoadMenu(UINT nIDResource) ? загружает меню из ресурсов и соединяет его с объектом класса CMenu. Меню может быть создано программным путем метода заполнения структур MENUITEMTEMPLATEHEADER и MENUITEMTEMPLATE и посредством вызова метода LoadMenuIndirect(const MUNUTEMPLATE *lpMenuTemplate). ° BOOL Attach(HMENU hMenu) ? пристыковка существующего меню к объекту класса CMenu. Если известен дескриптор меню, то можно определить указатель на соответствующий ему объект CMenu с помощью следующего метода static CMenu* PASCAL FromHandle(HMENU hMenu). ° BOOL DestroyMenu() ? разрушает объект CMenu и освобождает все ресурсы. Этот метод обычно не вызывается явно, так как он автоматически вызывается из деструктора. ° BOOL DeleteMenu(UINT uPosition, UINT uFlags) ? метод удаляет указанный элемент меню. uPosition ? определяет удаляемый элемент меню. uFlags ? определяет, как интерпретируется первый параметр. Если флаг равен MF_BYCOMMAND, то первый параметр интерпретируется как идентификатор пункта меню. Если параметр равен MF_BYPOSITION, то первый параметр определяет позицию элемента меню. Первый элемент имеет позицию ноль. ° BOOL TrackPopupMenu ( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRact = 0 ) ? метод осуществляет отображение всплывающего (контекстного) меню. Всплывающее меню может быть отображено в любом месте экрана. Метод автоматически отслеживает выбор пункта меню. nFlags ? может быть задан следующими константами: TPM_CENTERALIGN, TMP_LEFTALIGN, TMP_RIGHTALIGN ? для указания позиции выравнивания по горизонтали относительно координаты x, TMP_LEFTBUTTON, TMP_RIGHTBUTTON ? для определения кнопки мыши, выполняющей выбор пункта меню. Координаты x, y ? позиция меню. pWnd ? указатель на окно, в котором находится это меню. Параметр lpRect ? определяет прямоугольную область, в которой щелчок мыши не вызывает исчезновение меню. Если значение параметра NULL, то область ограничена окном меню. ° BOOL AppenedMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) и BOOL AppenedMenu(UINT nFlags, UINT_PTR nIDNewItem, const CBitmap* pBmp) Используются для добавления элемента в конец меню. Параметр nFlags может быть комбинацией следующих констант: MF_CHECKED ? переключаемый элемент, состояние ?включен? (отмечается галочкой). MF_UNCHECKED ? переключаемый элемент, состояние ?выключен? (галочки нет). MF_DISABLED ? элемент не лоступен. MF_ENABLED ? элемент доступен. MF_GRAYED ? 2серый? элемент (блокирован). MF_MENUBARBREAK ? элемент линейки меню. MF_OWNERDRAW ? самоотображаемый элемент., меня само отвечает за отображение элемента. MF_POPUP ? элемент меню имеет подменю. MF_SEPARATOR ? отображение горизонтальной разделительной линии. MF_STRING ? элемент является текстовой строкой. Параметр nIDNewItem ? в зависимости от первого параметра отпеделяет либо идентификаторор нового элемента, либо указатель (HMENU) подменю; игнорируется для значения MF_SEPARATOR. Параметр lpszNewItem определяет содержимое нового элемента. Параметр pBmp ? определяет указатель на объект класса CBitmap, который может использоваться в качестве содержимого строки меню. При этом первый параметр не может принимать значения MF_OWNERDRAW и MF_STRING. ° BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) и BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, const CBitmap* pBmp) ? поставляют новый элемент в позицию, определяемцю параметром nPosition. ° UINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck) ? устанавливает или сбрасывает галочку у элемента меню. Второй параметр может принимать два значения: MF_CHECKED и MF_UNCHECKED в комбинации с параметрами MF_BYCOMMAND и MF_BYPOSITION. ° UINT EnableMenuItem(UINT nIDEnableItem, UINT nEnable) ? метод устанавливает для указанного элемента одно из следующих значений: MF_DISABLES и MF_ENABLED, MF_GRAYED. ° UINT GetMenuItemCount() ? возвращает количество элементов меню. ° UINT GetMenuItemID(int nPos) ? метод возвращает идентификатор указанного элемента меню. ° Int GetMenuString(UINT nIDItem, lptstr lpString, int nMaxCount, UINT nFlags) и int GetMenuString(UINT nIDItem, CString& rString, UINT nFlags) ? определяют надпись на указанном элементе меню. ° BOOL RemoveMenu(UINT nPosition, UINT nFlags) ? метод удаляет указанный элемент меню. ° UINT GetMenustate(UINT nID, UINT nFlags) ? определяет состояние элемента или число элементов в раскрывающемся меню. Второй параметр определяет то, как интерпретировать первый элемент ? идентификатор или позиция элемента меню. Для раскрывающегося меню старший байт возвращаемого значения содержит число элементов в нем, младший байт ? набор флагов. Для меню верхнего уровня все возвращаемые значения являются набором флагов. ° Хотя сам редактор меню, предлагаемый Visual Studio.NET, весьма удобен, приведу структуру меня, то есть то, как оно хранится в текстовом файле ресурсов.
Как видите, меня имеет идентификатор IDR_MENU1, который, разумеется, имеет числовое выражение. Если мы посмотрим таблицу Resource Symbols, то увидим, что числовое выражение этого идентификатора 129 (у автора). Как вы наверно уже знаете, числовые значения идентификаторов хранятся в файле resource.h. Такие же идентификаторы имеет каждый элемент меню. Это очень важно, так как в программе мы фактически имеем дело не с меню, а с его элементами. Теперь разберем алгоритм установки меню в диалоговое окно. Для этой цели естественно нужно выбрать функция OnInitDialog. Определим в начале файла указатель cm: CMenu * cm;. Следующий шаг ? это создание объекта класса CMenu: cm = new CMenu;. Теперь загружаем шаблон меню из файла ресурсов: cm->LoadMenu(IDR_MENU!). таким образом, наш объект наполнился реальным содержанием. Наконец последнее, мы должны пристыковать получившийся объект к диалоговому окну. Это производится следующим действием This->SetMenu(cm); ?This?, как вы понимаете, указывает на объект ? диалоговое окно, SetMenu ? метод, осуществляющий желанную нами пристыковку. И все, этого уже достаточно, чтобы в созданном диалоговом окне появилось и меню. Да, не забудьте, закрывая окно, удалить меню из памяти, дабы не оставлять за собой мусор. Делается это очень просто: delete cm. Конечно, этого еще не достаточно для полноценного функционирования приложения, так как пункты меню должны работать, то есть при выборе пункта должна выполняться какая-то процедура. Функцию-обработчик можно сделать для каждого пункта меню. Делается это точно тек же, как для любых других элементов диалогового окна. Для этого, находясь в редакторе меню, нужно щелкнуть правой кнопкой мыши на нужном элементе меню и выбрать Add Event Handler. Далее, в появившемся окне выбирается имя функции и команда, которую вы хотите обрабатывать. Разумеется, этой командой будет COMMAND. Кроме того, в окне следует выбрать класс, где будет производиться обработка. Следует выбрать класс, объектом которого является наше окно. Далее, оказавшись в нужном файле и в нужной функции, можете вводить нужный нам фрагмент кода, который будет выполняться, когда будет выбран соответствующий пунк меню. В принципе этого уже достаточно, чтобы писать приложения с меню. Теперь обратимся к отдельному, но тесно связанному с меню вопросу ? клавишам акселераторам. Дело в том что этот ресурс используется в основном для быстрого доступа к элементам меню. Для того чтобы клавиша-акселератор была связана с соответствующим пунктом меню, нужно чтобы идентификаторы пункта меню и акселератора совпадали. Тогда обработчик пункта меню и клавиши будет одним и тем же. Но для работы акселератора нужно сделать еще две вещи. Во-первых, следует загрузить таблицу акселераторов в память. Сделать это можно там же, где вы загружаете меню. Но вот для диалогового окна (точнее в классе CDialog) подходящего метода нет. Придется воспользоваться функцие API: LoadAccelerators. Загружая таблицу, эта функция возвращает дискриптор загруженного ресурса. Следует запомнить этот дискриптор в какой-нибудь глобальной переменной. Наприметр, можно ввести дополнительное свойство в объект theApp. Первым аргументом функции является дескриптор приложения, который может быть с помощью глобальной функции AfxgetInstanceHandle(). Вторым аргументом является идентификатор таблици акселераторв, преобразованный с помощью макроса MAKEINTRESOURCE. Итак, таблица акселераторов загружена, что дальше? Дальше, и это последнее, следует подвергнуть дополнительной обработке сообщение, приходящее на окно. Для этого достаточно переписать метод PreTransleteMessage.
|