ComponentListener doesnt receive z-order changes


#1

It seems the ComponentListener currently has no way of being informed when the Component it is listening to has its z-order changed.

One minor irrelevant detail, the parameter name in the function definition for void Component::toFront (const bool setAsForeground) is different from the declaration (void Component::toFront (bool shouldAlsoGainFocus))


#2

True. I guess I should tweak it so that a parent gets a componentChildrenChanged() callback when a child moves.


#3

I’m not so sure that will help me with my use-case. I’m trying to develop a Component that has a transparent frame and an interior rectangle that draws with setOpaque(true). We talked about this in the other thread. After much consideration, and taking your input into account, I have decided that this is the best way to do it:

  • The main control Component will have setOpaque(false) and do its drawing in paint().
  • This control Component can be a juce::Button, any other Juce Component object, or a custom object
  • A helper Component will be created with setOpaque(true), that has a bounds inset from the main control
  • This helper Component will not draw at all, it only exists to clip out everything underneath it from drawing
  • The helper will sit underneath the main control in the z-order, follow the main control around.
  • The helper is not a child of the main Component, or a parent, but is instead a sibling.

Rather than have a “frame” or “shadow” object that moves around, my needs are served best by having a simple opaque clipping Component sit underneath the main object. It is less obtrusive, easier to generalize, and it lets me do all the drawing in a single function. This is important to me because of the way I have “connected edges” in the controls. Plus, like you said before the object that receives the user input also performs the drawing.

In order for the helper Component to properly follow around the main Component I need to know when the main Component is attached or detached from its parent, when the main Component is moved or resized, and when the main Component changes its position in the z-order. ComponentListener supports all of that except the z-order.

The problem with having ComponentListener receive componentChildrenChanged() when a child moves in the z-order, is that I’m not listening to the parent of the helper, I’m listening to the helper. The helper has no children. I suppose a work around is to addComponentListener to both the main control Component and also the helper’s parent but this seems bulky.


#4

If you tried to tell every component when its z-order changes, then you’d end up making a huge number of useless calls - every time you removed or added a component, you’d need to call all other other ones to tell them about it.


#5

I see what you mean. Okay, I can also listen to the parent and respond to componentChildrenChanged().

This is what I would do:

void componentChildrenChanged( Component& component )
{
  if (&component == background->getParentComponent())
  {
    int contentIndex = getIndexOfChildComponent (content);
    int backgroundIndex = getIndexOfChildComponent (background);
    if (backgroundIndex != contentIndex-1)
      background->toBehind (content);
  }
}

This is going to cause a recursive entry into componentChildrenChanged (because of the call of toBehind) but then the indexes will be right and we will exit the recursion.

So to be clear you are proposing adding a call to internalChildrenChanged() in every Component function that changes z-order (toFront, toBack, toBehind are all I can think of)?


#6

The version I checked in yesterday already does that. Like you say, there were only a couple of places where it needed changing.


#7

I picked up the changes, and everything worked exactly as expected, thanks.