При разработке интерфейсов на Delphi иногда возникает необходимость программно выделить определенные элементы всплывающего меню без их клика. Вопрос, который часто встречается среди разработчиков, заключается в том, как можно выделить конкретный элемент всплывающего меню (TPopupMenu), не совершая при этом его активацию.
Описание проблемы
Разработчик столкнулся с задачей выделения определенного элемента меню после его отображения с помощью метода Popup. Попытка использовать функцию Winapi.Windows.HiliteMenuItem не увенчалась успехом, так как всплывающее меню (TPopupMenu) отличается от меню бара (TMenu).
Пример кода всплывающего меню
object pmTest: TPopupMenu
OnPopup = pmTestPopup
Left = 32
Top = 24
object mTest1: TMenuItem
Caption = 'Test 1'
OnClick = mTest1Click
end
object mTest2: TMenuItem
Caption = 'Test 2'
OnClick = mTest2Click
end
end
Подтвержденное решение
По умолчанию свойство TPopupMenu.WindowHandle ссылается на окно приложения, а не на внутреннее окно (HWND), которое используется TPopupMenu для обработки сообщений WM_COMMAND. Это окно создается при вызове метода Popup(), и оно не обновляет свойство TPopupMenu.WindowHandle.
Для решения проблемы следует использовать свойство TPopupList.Window вместо TPopupMenu.WindowHandle в функции HiliteMenuItem. В unités Vcl.Menus имеется глобальный объект PopupList, который можно применить для этой цели.
procedure TMyForm.pmTestPopup(Sender: TObject);
begin
Winapi.Windows.HiliteMenuItem(PopupList.Window, pmTest.Handle, 1, MF_BYPOSITION or MF_HILITE);
end;
Если предыдущий способ не работает, можно использовать функцию Winapi.Windows.SetMenuItemInfo, которая не требует передачи HWND.
Обновление: После дополнительного рассмотрения было выяснено, что событие TPopupMenu.OnPopup срабатывает до отображения меню, а TPopupMenu может пересоздать меню после вызова OnPopup и перед его фактическим отображением. В этом случае рекомендуется использовать подкласс TPopupList, чтобы перехватить сообщение WM_ENTERMENULOOP, и затем можно будет модифицировать элементы меню.
type
TPopupListEx = class(TPopupList)
protected
procedure WndProc(var Message: TMessage); override;
end;
procedure TPopupListEx.WndProc(var Message: TMessage);
begin
inherited;
if (Message.Msg = WM_ENTERMENULOOP) and (Message.WParam = 1) then
begin
// модификация элементов pmTest по необходимости...
end;
end;
initialization
PopupList.Free; // освобождение "стандартного", "старого" списка
PopupList := TPopupListEx.Create; // создание нового
// Новый PopupList будет освобожден в блоке finalization модуля Menus.
end.
Заключение
Выделение элементов всплывающего меню в интерфейсе на Delphi может быть выполнено различными способами, включая использование свойства TPopupList.Window и функции SetMenuItemInfo, а также с помощью подклассирования TPopupList для перехвата сообщений. Важно понимать, в какой момент следует выполнять эти действия, чтобы достичь желаемого результата.
Проблема заключается в необходимости программного выделения элементов всплывающего меню в интерфейсе на Delphi без их активации.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.