[Bug] Specifying a ParentComponent for a PopupMenu causes it to lose keyboardFocus on item selection

Juce 7.0.8. Mac.

I have recently taken to making my MainComponent the parent of all PopupMenus (to keep them inside the mainComponent), so this has become an issue that I just noticed.

It occurs anywhere you use a PopupMenu, but I’m focusing on ComboBoxes here. I’m calling it a bug, but at the very least it’s an annoying inconsistency, especially if you were to mix using a parentComponent and not using a parentComponent for comboBoxes within the same project.

With a parentComponent, the ComboBox will lose focus on item selection.

Here is a simple test project:

ComboBoxFocusTest.zip (11.2 KB)

ComboBox 1 has no parent specified for the popup. ComboBox 2 has a parentComponent (the mainComponent) specified by assigning it a custom LookAndFeel:

class MainComponent  : public juce::Component
{
public:
    //==============================================================================
    MainComponent();
    ~MainComponent() override;

    //==============================================================================
    void paint (juce::Graphics&) override;
    void resized() override;

private:
    //==============================================================================
    // Your private member variables go here...
    juce::ComboBox cbox1 {"Box1"};
    juce::ComboBox cbox2 {"Box2"};
    
    class CustomLAF : public juce::LookAndFeel_V4
    {
    public:
        CustomLAF(MainComponent* main)
        : mainComponent(main) {}
        
        juce::Component* getParentComponentForMenuOptions (const juce::PopupMenu::Options& options)
        {
            return mainComponent;
        }
    private:
        MainComponent* mainComponent;
    };
    CustomLAF customLAF {this};

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

//==============================================================================
MainComponent::MainComponent()
{
    setWantsKeyboardFocus(true);
    
    juce::StringArray menuList = {"Item 1", "Item 2", "Item 3" };
    
    addAndMakeVisible(cbox1);
    cbox1.addItemList (menuList, 1);
    cbox1.setSelectedItemIndex(0, juce::NotificationType::dontSendNotification);
    cbox1.setHasFocusOutline(true);
    
    addAndMakeVisible(cbox2);
    cbox2.addItemList (menuList, 1);
    cbox2.setSelectedItemIndex(0, juce::NotificationType::dontSendNotification);
    cbox2.setHasFocusOutline(true);
    cbox2.setLookAndFeel(&customLAF);
    
    setSize (600, 400);
}

So ComboBox1 is focused by me clicking on it. It gets a focus outline. The menu opens. Without a parentComponent, selecting an item from the menu closes the menu and leaves the ComboBox focused (as it should be):

You could then use the keyboard (for example) to make selections.

But with a parentComponent specified for the popup in ComboBox2, selecting an item with the mouse (as soon as you click down) focuses on the parentComponent and the ComboBox loses its focus.

I tracked the issue down to these lines at the end of
Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryParent, FocusChangeDirection direction)

    // if no children want it and we're allowed to try our parent comp,
    // then pass up to parent, which will try our siblings.
    if (canTryParent && parentComponent != nullptr)
        parentComponent->grabKeyboardFocusInternal (cause, true, direction);

The problem is that canTryParent is always passed in as true from up the chain. So if the popupMenu has a parent, it always ends up focusing back on the parentComponent of it, i.e. the MainComponent.

1 Like

Thank you for reporting. A fix has been released on develop

1 Like