Для зарегистрированных пользователей |
|
Меню Visual Basic и Windows API
Сразу скажу, что у меня не было цели, рассказать обо всех функциях WinAPI для работы с меню. Зачем мучаться с ними, если проще всё сделать в VB. Вот то, что для VB недоступно, - это мы и рассмотрим. Visual Basic даёт программисту простой и удобный инструмент для создания меню. Но этот инструмент уступает по возможностям, прямой работе с меню через WinAPI. VB удобен и прост в использовании из-за того, что программисту не нужно заботиться о взаимодействии приложения с Windows. Это одновременно и его недостаток, т.к. программисту очень тяжело работать с системой напрямую, игнорируя VB. Всё выше сказанное напрямую связано с работой с меню через WinAPI. Дело в том, что меню в Visual Basic - специальный объект, не являющийся по сути настоящим меню Windows, хотя он и формирует меню в процессе исполнения. В VB меню задаётся набором пунктов, различающихся именем(или индексом) и степенью вложенности. В Windows меню - это объект, содержащий набор команд с определёнными идентификаторами. Если VB на выбор пункта меню отзывается событием типа Menu_CLick, то Windows отправляет окну - хозяину меню сообщение WM_COMMAND с соответствующими параметрами. VB не может правильно обработать сообщение от пункта меню созднного через API, так как "не понимает" его. Чтобы перехватывать такие сообщения требуется субклассирование. В Windows существует два типа меню: меню окна, и всплывающее меню. (В VB, меню окна составляют не вложенные пункты, а всплывающее меню формируется из вложенных). Подменю в Windows - это отдельные меню, связанные с вызывающим пунктом меню. Все функции предназначенные для работы с меню, находятся в модуле user32 и возвращают Long. Все параметры передаются ByVal. Работать с меню можно только через его манипулятор, поэтому рассмотрим функции предназначенные для получения этого манипулятора.
GetMenu(hWnd As Long) Эта функция получает манипулятор меню окна, заданного hWnd
GetSubMenu( hMenu As Long,nPos As Long) Эта функция получает манипулятор всплывающего меню, с которым ассоциирован пункт меню hMenu, под номером nPos, нумерация начинается с нуля.
GetSystemMenu(hWnd As Long, bRevert As Long) Получает манипулятор системного меню окна, заданного hWnd.Если bRevert присвоить ненулевое значение, системное меню будет восстановлено. При ошибке или восстановлении меню, функция возвращает 0.
IsMenu(hMenu As Long) - проверяет действителен ли манипулятор меню hMenu. Если да, возвращает ненулевое значение, иначе ноль.
GetMenuDefaultItem(hMenu As Long, fByPos As Long, gmdiFlags As Long) - функция определяет команду меню по умолчанию. hMenu-манипулятор проверяемого меню. fByPos - Флаг, если неравен нулю, возвращает позицию, иначе идентификатор. gmdiFlags - GMDI_GOINGTOPOPUPS, для поиска внутри связанных всплывающих меню. GMDI_USEDISABLED, для запрета пропуска заблокированных меню. Если функция не находит команды возвращает -1, иначе идентификатор или позицию команды.
GetMenuItemID(hMenu As Long, nPos As Long)-функция получает идентификатор команды меню. hMenu-манипулятор меню. nPos-позиция команды меню. Отсчёт начинается с нуля. Функция возвращает идентификатор, 0 если разделитель, -1 если с пунктом ассоциировано подменю.
GetMenuCheckMarkDimensions()-возвращает необходимые размеры маркера, для пометки команды меню. Возвращает Long-старшее слово которого(16 бит) содержит высоту, а младшее - ширину в пикселах. В отличие от всех остальных, прведённых здесь не поддерживается в Win16. Через эту функцию, я определил, что размеры маркера 13x13.
SetMenuDefaultItem(hMenu As Long, uItem As Long, fByPos As Long)-устанавливает команду меню по умолчанию. hMenu-манипулятор меню. uItem-команда для установки, -1 для сброса текущей команды по умолчанию. fByPos-ненулевое значение обозначает, что в uItem передана позиция, 0 - идентификатор. Функция возвращает ноль, в случае ошибки.
Теперь рассмотрим три функции, ради которых собственно и стоит использовать WinAPI.
ModifyMenu Alias "ModifyMenuA"(hMenu As Long, nPosition As Long, wFlags As Long, wIDNewItem As Long, lpNewItem As Any)-Мощная функция для изменения команды меню. Позволяет задавать растры для команд меню. ModifyMenu предпочтительнее AppendMenu, и InsertMenu, так, как не меняет расположение команд. hMenu-манипулятор меню. nPosition-изменяемая кманда меню. wIDNewItem-новый идентификтор команды. Вы должны передать идентификатор полученный GetMenuItemID для этой команды меню, иначе VB не узнает её. lpNewItem-новое значение для команды меню. wFlags-флаги управляющие изменением меню. MF_BITMAP-для замены текста команды растром. В lpNewItem нужно передать манипулятор растра. Его можно получить через свойство Handle объекта Picture. Пример: imgPicture.Picture.Handle. В этом случае Вы должны следить, чтобы содержимое контейнера PictureBox илм Image не менялось. MF_STRING-в lpNewItem задаётся текстовая команда. MF_SEPARATOR-команда превращается в разделитель. MF_BYCOMMAND-в nPosition передаётся идентификатор. MF_BYPOSITION-в nPosition передаётся номер команды, наxиная с нуля. Функция возвращает нулевое значение, в случае ошибки. иначе ненулевое. Устанавливает информацию GetLastError.
SetMenuItemBitmaps(hMenu As Long, nPosition As Long, hBitmapUnchecked As Long, hBitmapChecked As Long)- функция устанавливает маркеры для помеченного и непомеченного состояния. hMenu-манипулятор меню nPosition,wFlags - смотри ModifyMenu hBitmapUnChecked, hBitmapChecked-манипуляторы соответствующих растров. Если один из параметров, установлен в ноль, соответствующий маркер не используется. Если оба равны нулю, используются маркеры по умолчанию. На изображения используемые в качестве маркеров накладываются те-же ограничения, что и на растры, для ModifyMenu. Функция возвращает 0 при ошибке. Остальные значения свидетельствуют, об удаче.
TrackPopupMenu(hMenu As Long, wFlags As Long, x As Long, y as Long,nReserved As Long, lpRc As Rect)- Функция выводит всплывающее меню, в любой точке экрана. hMenu-маниулятор меню. x, y-координаты "всплывания". nReserved-должен быть равен нулю. lpRc-прямоугольник, щелчок внутри которого. не закрывает меню. Рекомендую объявить его ByVal lpRc As Long, и передавать ноль. wFlags-флаги управляющие "всплыванием". TPM_CENTERALIGN-x, y задают координаты центра меню. TPM_LEFTALIGN-по x выровнен левый край. TPM_RIGHTALIGN-по x выровнен правый край. TPM_LEFTBUTTON- меню вызывается левой кнопкой. TPM_RIGHTBUTTON- меню вызывается правой кнопкой. Возвращает 0 в случае ошибки, остльные значения обозначают успех. Устанавливает информацию GetLastError.
В завершении, я приведу код двух функций, для получения манипулятора меню заданного названием(caption) пункта, и позиции этого пункта в этом меню.
'получение позиции команды меню Public Function GetMenuPos(ByVal hMenu As Long, ByVal Caption As String) As Long Dim i As Long Dim max As Long Dim lres As Long Dim Result As Long Dim sData As String Dim sdLen As Long Result = -1 max = GetMenuItemCount(hMenu) If max = 0 Then GetMenuPos = -1: Exit Function For i = 0 To max - 1 sData = String$(256, 32) sdLen = Len(sData) + 1 lres = GetMenuString(hMenu, i, sData, sdLen, MF_BYPOSITION) If LCase$(Left$(sData, lres)) = LCase$(Caption) Then Result = i: Exit For Next i GetMenuPos = Result End Function
'Получение манипулятора меню Public Function SearchMenu(ByVal hMenu As Long, ByVal Caption As String) As Long Dim i As Long Dim lres As Long Dim max As Long Dim Result As Long lres = GetMenuPos(hMenu, Caption) If lres <> -1 Then SearchMenu = hMenu: Exit Function Debug.Print max max = GetMenuItemCount(hMenu) For i = 0 To max - 1 lres = GetMenuItemID(hMenu, i) If lres = -1 Then Result = SearchMenu(GetSubMenu(hMenu, i), Caption) Next i SearchMenu = Result End Function
|