I have this popup menu:
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
After showing the popup menu with the Popup
method, I need to programmatically HIGHLIGHT (not to click!) a specific menu item, so I tried this:
Winapi.Windows.HiliteMenuItem(pmTest.WindowHandle, pmTest.Handle, 1, MF_BYPOSITION or MF_HILITE);
But it does not work.
How can I programmatically HIGHLIGHT a specific popup menu item?
By default, the TPopupMenu.WindowHandle
property is set to the Application.Handle
window, not to the private HWND
that TPopupMenu
actually uses internally to actually dispatch its WM_COMMAND
messages to. That window is established when the TPopupMenu.Popup()
method is called, and it does not update the TPopupMenu.WindowHandle
property.
Try using the TPopupList.Window
property instead of the TPopupMenu.WindowHandle
property for the HWND
to pass to HiliteMenuItem()
. There is a global PopupList
object in the Vcl.Menus
unit:
procedure TMyForm.pmTestPopup(Sender: TObject);
begin
Winapi.Windows.HiliteMenuItem({pmTest.WindowHandle}PopupList.Window, pmTest.Handle, 1, MF_BYPOSITION or MF_HILITE);
end;
If that still does not work, then try the Win32 SetMenuItemInfo()
function instead, which does not take an HWND
for input:
procedure TMyForm.pmTestPopup(Sender: TObject);
var
mii: MENUITEMINFO;
begin
ZeroMemory(@mii, sizeof(mii));
mii.cbSize := sizeof(mii);
mii.fMask := MIIM_STATE;
mii.fState := MFS_HILITE;
Winapi.Windows.SetMenuItemInfoW(pmTest.Handle, 1, True, mii);
end;
UPDATE: Upon further review, the TPopupMenu.OnPopup
event is fired BEFORE the menu is made visible, and TPopupMenu
may recreate the menu AFTER OnPopup
has been called and BEFORE the menu is actually shown. So, your best bet is likely to subclass the TPopupList
window so you can intercept the WM_ENTERMENULOOP
message, then customize your menu items at that point. For example:
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
// customize pmTest items as needed...
end;
end;
initialization
Popuplist.Free; //free the "default", "old" list
PopupList := TPopupListEx.Create; //create the new one
// The new PopupList will be freed by
// finalization section of Menus unit.
end.