MouseListener::mouseUp() not being called for Component


#1

I’m wondering if anyone can help me out here…

I have a Component (let’s call it the Parent) which contains a Drawable that is transform scaled to the same size as it, basically creating an object that can hold a scalable Image or SVG. The Parent has a MouseListener registered, with wantsEventsForAllNestedChildComponents=true. So, I now have a convenient proxy object that won’t go away when I switch out the underlying Drawable.

The problem is that I can trigger the mouseDown and mouseDrag methods on my listener class, but not the mouseUp. Doing this on a Label instead of a Component (also with a separate MouseListener) works as expected.

I haven’t seen this issue before in the Forums. Any ideas on what I could do to fix this, or if it’s a Juce bug (which I doubt)?

Thanks!
Sean


#2

Well, mouse-up events are always to all the listeners, just like other types of mouse-event… The only thing that would interrupt that process would be if one of the mouse-up callbacks deletes the component that’s being clicked - perhaps something is doing that?


#3

There isn’t anything like that as far as I can tell. I haven’t been able to debug it because I’m using juce_amalgamated, and Visual Studio doesn’t properly align symbols with lines somewhere around the 65k line mark :slight_smile: so once I get switched over to the .lib, I’ll be able to dig more.

Thanks,
Sean


#4

Don’t use the .lib, just use the introjucer option which directly includes the non-amalgamated code.


#5

Yes, it turns out I actually was deleting the underlying component when clicking on it. I thought that the parent Component with the bound MouseListener was being set as the componentUnderMouse, but in fact it was the lowest child, the image I was deleting on mouseDown.

Thanks for your help,
Sean

ps - I’m using juce_amalgamated{1…4}.cpp now and it’s MUCH easier to debug.


#6

Although, this does bring up a question… If I have a MouseListener on a parent Component which contains a Drawable as a child, and causing a mouseDown on that parent requires the Drawable to not be removed for the subsequent mouseUp to be called (because the Drawable has been set as the componentUnderMouse), then I can never do something like creating a button which flips two images in and out based on a click. For example, if I wanted to do something like create my own button class with a separate push-down image.

What would be the proper way to do that? Is there a way to force a recalculation of what is under the mouse, in between replacing the underlying Component and the mouseUp event? Or a way to stop mouse event evaluation at the Component so it becomes the componentUnderMouse?

Sean


#7

You could make the drawable ignore mouse-clicks, and just let the clicks go directly to its parent?


#8

I got this to work only by calling setInterceptsMouseClicks(false, false) on the Drawable.

It took me a while to figure this out because I had called setInterceptsMouseClicks(true, false) on the parent Component, but that doesn’t work. After reading the documentation more carefully, it appears that the case is unsupported where one would want the object to be clicked on, but none of the children.

On investigating why, it seems that even though Component::hitTest() does check the intercept flags, Component::getComponentAt() recurses through the tree of Components and will return the deepest Component it finds that returns true for the hitTest. If I don’t explicitly call setInterceptsMouseClicks(false, false) on a Component, it won’t stop recursing.

I guess it’s not technically a bug because it works as documented, but I think the case where the target Component is clickable and blocks children would be useful, such as the case where you want to place arbitrary objects behind your component, and don’t want to worry about setting each of their intercept rules. If getComponentAt() only did a shallow hit test for that object if its allowChildMouseClicksFlag==false, it would gain this behavior.

Sean