Retrieving PopupMenu int value?

This is the example in the docs, how do I just return the int to my class? You can’t access class variables in the function so I don’t get how this is useful?

I also tried passing a static function as a callback, but again you can’t access any class variables. I just want the int value in my class.

    m.showMenuAsync (PopupMenu::Options(),
                     [] (int result)
                     {
                         if (result == 0)
                         {
                             // user dismissed the menu without picking anything
                         }
                         else if (result == 1)
                         {
                             // user picked item 1
                         }
                         else if (result == 2)
                         {
                             // user picked item 2
                         }
                     });

You can’t with using showMenuAsync. The hole point of that idiom is to kick of a task and be notified later, when it’s finished – the user selected an item from the menu. You may capture this (put it into the square brackets) to have access to your class instance inside the callback. Make sure that this still exists, as the user might click the menu any time (or never). For components, there is a built in solution for that using:

[safeThis = SafePointer(this)](auto result) {
  if (safeThis) // Now you are safe to do what you want.
}

If you want to block the UI until the user selects something you may use a modal version (without the async). You’ll have to enable that in your Projucer settings or set the preprocessor macro yourself (there are other tutorials for that) but this is most likely not what you want for a popup menu. You’d essentially freeze your entire application aside from the audio thread.

1 Like
class PopupButton : public juce::DrawableButton
{
public:
    PopupButton() 
    {
        onClick = [this]
        {
            
            juce::PopupMenu menu;
            
           /** add menu item */
          
            menu.showMenuAsync (juce::PopupMenu::Options(), action (idx));
            
        };
    }
    
    
    //==============================================================================
    
    std::function<void(int)> action (int result)
    {
        return [this] (int result)
        {
            idx = result;
            
            switch (idx)
            {
                default:
                    break;
            }
        };
    }
    
private:
    int idx { 0 }; // nothing selected
    
    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PopupButton)

};
1 Like

You pretty much always should use withDeletionCheck in your menu Options() as well.

In a plugin we pretty much always use this pattern:

        PopupMenu m
        m.addItem ("Do something", [this]() { doSomething(); });

        m.showMenuAsync (PopupMenu::Options().withDeletionCheck (*this).withTargetComponent (*this).withParentComponent (
                findParentComponentOfClass<POPUP_MENU_PARENT_CLASS>()));

Which puts the menu in a fixed place, doesn’t crash if *this is deleted while the menu is still open and pins the menu to the scaled plugin UI (instead of floating it as a new OS window). Where POPUP_MENU_PARENT_CLASS is a define pointing at our scaled UI top level component.

1 Like

Thanks, this was exactly the kind of example I was looking for, I suppose I really need to spend some time getting up to date with Lambdas and the like, I don’t really understand them. I’m pretty oldschool but I suppose it’s the updated version of function piointers.

Thanks everyone else for your help, it was all good info!

Not really. std::function is the new ‘function pointer’. But… lambdas are magic! Huge design shifts happen when you understand them.

1 Like