Mouse Events for child ImageComponents

#1

Hi!

I’m hoping there’s a simple answer to this, as it seems a simple problem! It’s got me stumped though!

I’ve got a parent Component. I have 3 non-overlapping ImageComponents which are children of the parent.

When I mouseover the child components I would like them to respond. However, no matter what I try, I cannot get any mouse events from the child components! Yes, I can use a MouseListener so that they receive events from the parent, but the only events fired from the parent are mouseEnter and mouseExit when the mouse goes outside the bounds of the parent.
There are no events when the mouse is inside the parent and moving over the child components.
I saw a post where it was suggested that the parent should fire a mouseExit when the mouse moves over a child component - is that correct? If so, I’m not seeing that.
Any ideas?

Thanks in advance!

Mark

0 Likes

#2

Are you listening in the parent for mouse events from the children?
If you want to do that, you first have to add a mouse listener for the children. To do so, add the following line in the parent (e.g. in the constructor):
“childComp.addMouseListener(this, true);”

0 Likes

#3

That is really not necessary. Either the ImageComponent can react by its own, by inheriting and overriding mouseDown, or you call on your parent:
setInterceptMouseClicks (true, false);

This will make the component handle all mouse events by itself, also the ones, that happen on their child components.

Only if you need to forward events from a specific child component, but not for others, then you can use a mouseListener. But a clever hierarchy usually avoids that.

0 Likes

#4

That’s what’s confusing - this should just work without MouseListeners (and I’m sure it has done in the past, we have built a lot of GUIs using Juce!)

0 Likes

#5

So you are inheriting the ImageComponent and overriding the mouse events, like mouseDown(), mouseEnter() etc?

what I would look for:

  • make sure to use the override keyword in the header, to let the compiler check for typos
  • check the size (but otherwise you wouldn’t see the image)
  • check for other overlapping components

I looked into ImageComponent’s sources, it all looks like default Component behaviour. No custom hitTest() or alike…

0 Likes

#6

Yep, I have created an ImageComponent subclass which overrides mouseEnter and mouseExit. They are the only mouse events I need from the child components. Definitely marked them as override.

0 Likes

#7

Very strange. I tried here, and it works normal.

Last idea, maybe accidentaly inherited the events as private?

For reference:

// MainComponent.h
#pragma once

#include "../JuceLibraryCode/JuceHeader.h"

class MyImage : public ImageComponent
{
public:
    MyImage (const String& name) : ImageComponent (name) {}
    void mouseEnter (const MouseEvent& e) override { DBG ("Enter " << getName()); }
    void mouseExit (const MouseEvent& e) override { DBG ("Exit " << getName()); }

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MyImage)
};

class MainComponent   : public Component
{
public:
    MainComponent();
    ~MainComponent();

    void paint (Graphics&) override;
    void resized() override;

private:
    MyImage img1 { "Rosencreutz" };
    MyImage img2 { "Guildenstern" };

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
// MainComponent.cpp
#include "MainComponent.h"

//==============================================================================
MainComponent::MainComponent()
{
    addAndMakeVisible (img1);
    addAndMakeVisible (img2);
    setSize (600, 400);
}

MainComponent::~MainComponent()
{
}

//==============================================================================
void MainComponent::paint (Graphics& g)
{
    // (Our component is opaque, so we must completely fill the background with a solid colour)
    g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
}

void MainComponent::resized()
{
    img1.setBounds (getLocalBounds().withWidth (getWidth() / 2).reduced (10));
    img2.setBounds (getLocalBounds().withLeft  (getWidth() / 2).reduced (10));
}
0 Likes

#8

Right, I think I’ve found the issue. I was calling setInterceptMouseClicks(false, false) in the constructor of my ImageComponent subclass. I had assumed that only had an effect on mouse clicks, not all mouse events?!

0 Likes

#9

Ah, good catch! It intercepts in hitTest afaik, so yes, it affects all mouse events. That’s slightly misleading the name…

1 Like

#10

Yes, it’s a misleading name and no mention in the documentation that it kills all mouse events!

“Setting this to false is an easy way to make a component pass its mouse-clicks through to the components behind it.”

0 Likes

#11

Thanks for all your help @daniel, much appreciated!

0 Likes

#12

usually if the docs aren’t clear, it’s time to command-click on the symbol in question and look at the source code to get an answer.

0 Likes

#13

To be fair, it mentions to “Change[s] the default return value for the hitTest() method.” - but that would only tell you something, once you had more exposure with mouse handling in general.

In this method you only see the flags for hitTest, so an average user wouldn’t make that connection immediately.

Since it is specifically called “mouseClicks”, an addition, that this affects ALL mouse events wouldn’t hurt IMHO.

0 Likes

#14

The point is I didn’t suspect that setInterceptMouseClicks was the source of my problem, since the problem was not mouse click-related. I have been using Juce for a long time and make a point of understanding what’s going on under the hood.

0 Likes

#15

Exactly, all it needs is an additional sentence in the docs :slight_smile:

1 Like

#16

Thank you for tracking this down so other people can see this too.

I’ll get the docs updated.

1 Like