Button appears during mouseover

Is this the right way to have a button appear on a component when the user mouse-overs its parent?

class Row : public Component
{
public:
    Row()
    {
        addAndMakeVisible(buttonAppearsDuringMouseOver);
        buttonAppearsDuringMouseOver.addMouseListener(this, false);
    }

    void paint (Graphics& g) override
    {
        g.fillAll (Colours::darkcyan);
    }

    void resized() override
    {
        buttonAppearsDuringMouseOver.setBounds(getLocalBounds().withWidth(50).reduced(2));
    }

    void mouseEnter(const MouseEvent&) override
    {
        buttonAppearsDuringMouseOver.setVisible(true);
    }

    void mouseExit(const MouseEvent&) override
    {
        buttonAppearsDuringMouseOver.setVisible(false);
    }

    TextButton buttonAppearsDuringMouseOver{"PUSH"};
};

You don’t need

buttonAppearsDuringMouseOver.addMouseListener(this, false);

Component handles the MouseListener for you

Rail

1 Like

Doesn’t work without that. As the mouse moves over the button it disappears. (i.e. exits the parent component and enters the child component).

My solution works but has a completely unnecessary set of calls to setVisible when the mouse moves between components.

As a PIP … my first PIP :slight_smile:

/*******************************************************************************
 The block below describes the properties of this PIP. A PIP is a short snippet
 of code that can be read by the Projucer and used to generate a JUCE project.

 BEGIN_JUCE_PIP_METADATA

  name:             MouseOver

  dependencies:     juce_core, juce_data_structures, juce_events, juce_graphics, juce_gui_basics
  exporters:        vs2017

  type:             Component
  mainClass:        MyComponent

 END_JUCE_PIP_METADATA

*******************************************************************************/

#pragma once


class MyComponent   : public Component
{
public:
    MyComponent()
    {
        setSize (600, 400);
        addAndMakeVisible(row);
    }

    void paint (Graphics& g) override
    {
        g.fillAll (Colours::black);
    }

    void resized() override
    {
        row.setBounds(getLocalBounds().withSizeKeepingCentre(getWidth() - 40, 25));
    }

    class Row : public Component
    {
    public:
        Row()
        {
            Component::setName("ROW");
            addAndMakeVisible(buttonAppearsDuringMouseOver);
            buttonAppearsDuringMouseOver.addMouseListener(this, false);
        }

        void paint (Graphics& g) override
        {
            g.fillAll (Colours::darkcyan);
        }

        void resized() override
        {
            buttonAppearsDuringMouseOver.setBounds(getLocalBounds().withWidth(50).reduced(2));
        }

        void mouseEnter(const MouseEvent&e) override
        {
            DBG("mouseEnter " + e.eventComponent->getName());
            buttonAppearsDuringMouseOver.setVisible(true);
        }

        void mouseExit(const MouseEvent&e) override
        {
            DBG("mouseExit " + e.eventComponent->getName());
            buttonAppearsDuringMouseOver.setVisible(false);
        }

        TextButton buttonAppearsDuringMouseOver{"PUSH"};
    };

private:
    Row row;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MyComponent)
};

I’m not sure if it will work, but maybe try to set setInterceptsMouseClicks (false, false) on the Textbutton.
The idea is, it will exclude it from hitTest, so the mouseEnter and mouseExit on the button would no longer happen. But the TextButton will receive the mouse callbacks from listening to the parent.
So the last thing will be to check on mouseDown (or mouseUp), if the event is in the TextButton’s bounds.

1 Like

That makes sense.

Aah… well if you add it, don’t forget to removeMouseListener() in the destructor.

Rail