How to modify existing main menu

I am trying to just add an About menu item to the main menu in an app, but am having a heck of a time trying to get access to that main menu (the one on top of the screen on Mac, and under the title bar on PC). I tried getting to it using getMenuBarComponent() at the end of my DocumentWindow’s constructor, but it is nullptr at that point in time. There is a menu visible up top (on the Mac), but where is it in code? Is it not accessible? Do I have to make my own menu, even though I only want to add one item to the existing menu? I don’t want to mess with any of the stuff that is there by default, just add About…, and don’t know how I would add the code behind those show/hide/hide others menu items. All I can find are examples and discussions of custom menus being created from scratch. (I will need to do this for PC as well, but some of the code that looks like it might help only seems to be in the mac .mm file.)

Take a look at MenuBarModel::setMacMainMenu. You can use the extraAppleMenuItems argument to append list items to your application’s main menu.

But that only works for Mac, and expects a MenuBarModel to be created first. Does that mean that I cannot just modify the existing menu somehow? There is certainly a menu there, with our app’s name at the top. Can that not be queried and modified? And how to do any of this on PC? That function is Mac only.

This also returns NULL when called at the end of the DocumentWindow’s constructor (and again, is Mac only).

juce::MenuBarModel* model = juce::MenuBarModel::getMacMainMenu();

True, but it’s very easy to create a MenuBarModel that does nothing.

No, you can modify the existing menu by passing extraAppleMenuItems to setMacMainMenu.

struct Model : public juce::MenuBarModel
{
    Model()
    {
        juce::PopupMenu menu;
        menu.addItem ("Foo", [] { DBG ("Foo"); });
        menu.addItem ("Bar", [] { DBG ("Bar"); });
        setMacMainMenu (this, &menu);
    }

    ~Model() override
    {
        setMacMainMenu (nullptr, nullptr);
    }

    juce::StringArray getMenuBarNames() override { return {}; }
    juce::PopupMenu getMenuForIndex (int, const juce::String&) override { return {}; }
    void menuItemSelected (int, int) override {}
};

class MainComponent final : public juce::Component
{
public:
    // omitted for brevity

private:
    // share the menu between all main window instances
    juce::SharedResourcePointer<Model> model;
};

For me, the above code adds two entries to the main “app name” menu, and leaves the existing entries intact.

Windows doesn’t have a “main menu” concept like macOS. On PC, you’ll need to create your own menu bar, owned by the window, and set up an appropriate MenuBarModel to provide the menu’s behaviour.

1 Like