In Delphi VCL, I'm trying to identify whether a TMenuItem is a top-level menu bar item (a MenuBarItem) as opposed to a regular submenu item.
I'm currently using this check:
if aItem.Count > 0 then
But this returns True for both top-level menu items (e.g., "File", "Edit" in the main menu bar) and submenu items that have their own children (like "Recent Files" under "File").
Is there a more reliable way—perhaps using TMenuItem properties or GetMenuItemInfo from the Windows API—to distinguish true menu bar items from submenu items with children?
i'm using this:
function IsMenuBarItem(aMenu: TMainMenu; aItem: TMenuItem): Boolean;
var
LInfo: MENUITEMINFOW;
LHMenu: HMenu;
I: Integer;
begin
Result := False;
LHMenu := aMenu.Handle;
ZeroMemory(@LInfo, SizeOf(LInfo));
LInfo.cbSize := SizeOf(LInfo);
LInfo.fMask := MIIM_SUBMENU;
for I := 0 to GetMenuItemCount(LHMenu) - 1 do
begin
if GetMenuItemInfoW(LHMenu, I, True, LInfo) then
begin
if LInfo.hSubMenu = aItem.Handle then
begin
Result := True;
Exit;
end;
end;
end;
end;
is possible to avoid iterating all items in the main menu if i trying to determine whether a given TMenuItem is a menu bar item, using only information from the TMenuItem itself !
---
🧩 Context:
The reason I'm doing this is to work around the automatic access key (Alt + key) assignment that Windows applies when menu items don't have an & in their caption.
Even after setting:
TMainMenu.AutoHotkeys := maManual;
the issue persisted.
I'm working in a Right-to-Left (BiDiMode) environment with OwnerDraw := True, and the system still assigns hotkeys unless the & is explicitly added to the menu captions.
👉Hint: the TMainMenu is hosted by TToolBar and not the Form !
--
🛠️ MySolution: Add "&" to Non-MenuBar Items
Here's the utility I use to ensure all non-menu bar items have an & prefix:
procedure TdmUI.FixMenuCaptions(aMenu: TMainMenu);
var
I: Integer;
procedure FixItem(aItem: TMenuItem);
var
J: Integer;
begin
if (Pos('&', aItem.Caption) = 0) and
(not aItem.IsLine) and
(not IsMenuBarItem(aMenu, aItem)) then //or (aItem.Count > 0) or (aItem.Tag <> 2)
aItem.Caption := '&' + aItem.Caption; // Add & if missing
for J := 0 to aItem.Count - 1 do
FixItem(aItem.Items[J]);
end;
begin
for I := 0 to aMenu.Items.Count - 1 do
FixItem(aMenu.Items[I]);
end;
This approach above ensures that only submenu items get the &, preserving the expected behavior on the menu bar, especially in right-to-left and owner-drawn setups.