How to add TMenuItem under Project1 and above Quit on the screenshot below?
I have created a TMenuBar with property UseOSMenu checked. The first TMenuItem I added is the second one in the main bar...
You can do this by assigning a TMenuBar of IItemsContainer implementing class to the Application.ApplicationMenuItems property.
Example:
If there was a menu bar component on the form called MenuBar1, then you would just call the following in your forms constructor (or OnCreate).
Application.ApplicationMenuItems := Menubar1;
You can then have a second TMenuBar component to define the other menu items.
I'd point you to the wiki topic on the ApplicationMenuItems property, but it has no additional help...
http://docwiki.embarcadero.com/VCL/XE2/en/FMX.Forms.TApplication.ApplicationMenuItems
I have created a unit to try to manage what I would like... With it, I can use a specific TMenuItem... and move its subitems to the application submenu... (I still don't know how to add one from scratch...)
I also use the answer from Mehmed Ali to manage the separators...
unit uMenu;
interface
uses
FMX.Dialogs, System.SysUtils,
FMX.Menus
{$IFDEF MACOS}
,Macapi.ObjectiveC,MacApi.AppKit,MacApi.Foundation,FMX.Platform.Mac
{$ENDIF}
;
type
ManageMenu = class
private
{$IFDEF MACOS}
class procedure FixSeparatorItemsForMenuItem (MenuItem: NSMenuItem);
class procedure MoveItemsToMacApplicationMenu(source, target: NSMenuItem); overload;
class procedure MoveItemsToMacApplicationMenu(index: Integer); overload;
{$ENDIF}
public
class procedure FixSeparatorItemsForMac;
class procedure MoveItemsToMacApplicationMenu(index: Integer; menu: TMainMenu); overload;
class procedure MoveItemsToMacApplicationMenu(index: Integer; menu: TMenuBar); overload;
end;
implementation
{ ManageMenu }
{$IFDEF MACOS}
class procedure ManageMenu.FixSeparatorItemsForMenuItem(MenuItem:NSMenuItem);
var
i : Integer;
subItem: NSMenuItem;
begin
if (MenuItem.hasSubmenu = False) then exit;
for i := 0 to Pred(MenuItem.submenu.itemArray.count) do
begin
subItem := MenuItem.submenu.itemAtIndex(i);
if (subItem.title.isEqualToString(NSSTR('-'))= True) then
begin
MenuItem.submenu.removeItemAtIndex(i);
MenuItem.submenu.insertItem(TNSMenuItem.Wrap(TNSMenuItem.OCClass.separatorItem), i);
end
else
begin
FixSeparatorItemsForMenuItem(subItem);
end;
end;
end;
{$ENDIF}
class procedure ManageMenu.FixSeparatorItemsForMac;
{$IFDEF MACOS}
var
NSApp : NSApplication;
MainMenu: NSMenu;
AppItem : NSMenuItem;
i : Integer;
{$ENDIF}
begin
{$IFDEF MACOS}
NSApp := TNSApplication.Wrap(TNSApplication.OCClass.sharedApplication);
MainMenu := NSApp.mainMenu;
if (MainMenu <> nil) then
begin
for i := 0 to Pred(MainMenu.itemArray.Count) do
begin
AppItem := mainMenu.itemAtIndex(i);
FixSeparatorItemsForMenuItem(AppItem);
end;
end;
{$ENDIF}
end;
{$IFDEF MACOS}
class procedure ManageMenu.MoveItemsToMacApplicationMenu(source, target: NSMenuItem);
var
iLoop, iMax: Integer;
subItem : NSMenuItem;
begin
if (source.hasSubmenu = False) then exit;
iMax := Pred(source.submenu.itemArray.count);
for iLoop := iMax downto 0 do
begin
subItem := source.submenu.itemAtIndex(iLoop);
source.submenu.removeItemAtIndex(iLoop);
target.submenu.insertItem(subItem, 0);
end;
// Hide the parent
source.setHidden(True);
end;
{$ENDIF}
{$IFDEF MACOS}
class procedure ManageMenu.MoveItemsToMacApplicationMenu(index: Integer);
var
NSApp : NSApplication;
MainMenu: NSMenu;
source : NSMenuItem;
target : NSMenuItem;
begin
NSApp := TNSApplication.Wrap(TNSApplication.OCClass.sharedApplication);
MainMenu := NSApp.mainMenu;
if (MainMenu <> nil) then
begin
begin
if (MainMenu.itemArray.count > 1) then
begin
source := mainMenu.itemAtIndex(Succ(index));
target := mainMenu.itemAtIndex(0);
MoveItemsToMacApplicationMenu(source, target);
end;
end;
end;
end;
{$ENDIF}
class procedure ManageMenu.MoveItemsToMacApplicationMenu(index: Integer; menu: TMainMenu);
begin
{$IFDEF MACOS}
MoveItemsToMacApplicationMenu(index);
{$ELSE}
// (menu.Children[Succ(index)] as TMenuItem).Visible := False;
// menu.RemoveObject(...);
// ... I don't knwo how to remove items on Windows ;o(((
{$ENDIF}
end;
class procedure ManageMenu.MoveItemsToMacApplicationMenu(index: Integer; menu: TMenuBar);
begin
{$IFDEF MACOS}
MoveItemsToMacApplicationMenu(index);
{$ELSE}
if (menu.ChildrenCount > Succ(index)) and (menu.Children[Succ(index)] is TMenuItem) then
begin
// (menu.Children[Succ(index)] as TMenuItem).Visible := False;
// menu.RemoveObject(...);
// ... I don't knwo how to remove items on Windows ;o(((
// menu.BeginUpdate;
// menu.RemoveObject((menu.Children[Succ(index)] as TMenuItem));
// menu.RemoveFreeNotify((menu.Children[Succ(index)] as TMenuItem));
// menu.DeleteChildren;
// (menu.Children[Succ(index)] as TMenuItem).View.Visible := False;
// .Free;
// (menu.Children[Succ(index)] as TMenuItem).Destroy;
// menu.EndUpdate;
end;
{$ENDIF}
end;
end.
It works as expected and it is what I want on OSX...
procedure TfrmMain.FormActivate(Sender: TObject);
begin
if not bAlreadyActivated then
begin
bAlreadyActivated := True;
ManageMenu.FixSeparatorItemsForMac;
ManageMenu.MoveItemsToMacApplicationMenu(0, MainMenu1);
end;
end;
but now, I have an issue on Windows because whatever I try, I still have the menu I added for Mac displayed under Windows... ;o(
As of Delphi XE7, the Application.ApplicationMenuItems
property no longer exists.
You now have to create a TMainMenu
item to get the expected result, no need to assign it. Just drop a TMainMenu
on to your main form and add your items, and they will appear in the OSX application menu.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With