How to setBounds without changing children?


#1

Hi,

I’ve found a strange behaviour, and I don’t understand how to solve it.

Typically, I’ve a main component (square : 256x256) containing few other components (circles that fit perfectly inside the square, radius:128)

I want to add a label to the top left of the main component, enlarging the bounds.

I’ve tried (pseudo) code like this:

   mainBB = mainComponent->getBounds();
   label = new label;
   // position label so that it's bottom right corner is on the top left corner of mainComponent 
   labelBB = label->getBounds();
   finalBB = mainBB.getUnion(labelBB.translated(- mainBB.topLeftCorner);
   newTopLeftCornerDiff = mainBB.topLeftCorner - labelBB.topLeftCorner;
   labelBB.setTopLeftCorner(0,0); // Now make it relative to parent
   addAndMakeVisible(labelBB);
   mainComponent->setBounds(finalBB);

This works, but previous child component are now shifted to the top left of newTopLeftCornerDiff.

So, I’ve added :

   addAndMakeVisible(labelBB);
   // Shift previous child component
   for all child, child->setTopLeftPosition(child->topLeftPosition + newTopLeftCornerAbsDiff)
   mainComponent->setBounds(finalBB);

But because the 2 setBounds calls are not transacted, I see the child component going down (just after setTopLeftPosition) and before mainComponent->setBounds, and then fitting correctly.

I’ve also tried to hide it before moving it (to avoid drawing it on the bad position), and making it visible afterward, but it seems the parent doesn’t care about this, and still the child component pop down and then back to the right position.

So, is there a way to set the bounds of a component without actually repainting it (I’ve debugged the code, and the child component doesn’t even repaint while being moved), or to enlarge a parent component without moving its children absolute position ?

Thanks, this popping artifact is terribly distracting.


#2

Is all of this code inside the same method? The only way it could repaint would be if the message-loop was being allowed to run in-between your first and second blocks of code.

And you’re doing all this on the normal message thread, right?


#3

Yes all is inside a timer callback (because it’s being animated).

I’ve tried many other things since (like removing the children from the main component and adding them to the desktop, changing main component’s bound and readding child like in jucedemo, splitting in 2 timers callback (one adding child to desktop, one adding back to main component)) but still doesn’t work without degradable visual effects (adding to desktop make the component flickering (it disappear and then appear again)).

In fact, I was hoping for a enlargeComponentWidthAndHeight() method that would keep child component at same place, but it looks like that the way Windows does this doesn’t allow such thing without initial visual feedback.

Anyway, I’ve limited the main component bounds at first because I thought it would take too much resources (the main component is transparent), but I guess I’ll have to set the bounds to the final size directly in the construction.


#4

But there’s really no way it can redraw unless the message loop runs… If I were you, I’d:

  • stick a breakpoint at the start of the routine
  • hit this bp, then add one in the MessageManager dispatch message routine, or the windowing paint callback
  • run on, and see if a callback happens before the end of the routine.

#5

I’m sure the child component DOESN’T repaint, but as soon as I “setBound” the main component (let’s say I move the top left corner of (-10px, -10px) , the child component window goes up 10px, and left 10px), no repainting occurs, but the window content is translated.
Then, the code reach the line childComponent->setBounds(+10, +10) and the child component window is moved back to the previous position, still without calling repaint on the child component (it can’t as it is in the message thread).
This makes the child component window “popping” up for a small fraction of second which is very disturbing.

What I’m asking is “is it possible to resize a component without physically moving its child component in one shot ?”

If I can’t, I’ll make the main component size directly of the final size.


#6

Oh, you’re actually moving a desktop window? I thought you were talking about lightweight ones.

Did you try just moving the child comps before moving the parent? If that doesn’t work, I guess you’re at the mercy of the window manager…


#7

I guess that instead of jumping up, they will jump down.

Under Windows, there is a DeferWindowPos that allows adjusting some window positions in one shot (so this case doesn’t happen, I guess?)

The main component is a desktop component (it’s a circular popup menu).


#8

No, I’m not sure they will jump down - that can’t happen until it gets repainted, which (probably) won’t happen before the window moves. Worth a try, anyway.


#9

Tried with setting the bounds beforehand, but the window now bump down (well doesn’t work).

So finally, I’ve created the main component with the initial bounds set to the largest position and that did it.

I’ll post it in the component section, as it’s a really cool menu to use.