Skin layoutChildren: when to get bounds of child nodes?

Werner Lehmann lehmann at
Wed Jul 30 15:12:16 UTC 2014


thanks a lot for this elaborate explanation :)  Here's an image of what 
I am talking about.

child1 is one of the labels in a hbox, e.g. "Query" or "Result"
child2 is the blueish region. It needs to be positioned under one of 
those labels. I am doing this with translateX and prefWidth.

On 28.07.2014 07:38, Martin Sladecek wrote:
> The super.layoutChildren should size every child of the control (which
> is VBox), but not child's children. The control must finish the layout
> before children can do theirs. If you need to do layout on some child
> before that, you can call .layout() on it. It will do it's layout using
> it's current size. You should have all the bounds correct after that call.

> But that would not work in your case anyway. You have both childs in a
> HBox, which takes care of resizing the children. This means you need to
> layout the HBox to get children size and in order to do that, you need
> HBox to be at it's final size, which will happen during the VBox layout.
> So your steps would be:
> 1) super.layoutChildren() - VBox is resized to Controls content size
> 2) now the VBox is resized, you can call vbox.layout()
> 3) now HBox is resized, so call hbox.layout()
> 4) children are resized. They have correct layout bounds now. But in
> order to get correct boundsInParent (but maybe you really need layout
> bounds?), you need to call .layout() on children too.

I my tests it was sufficient to do this:

layoutChildren() {
   bip = child1.getBoundsInParent()
   if (bip.getMinX() == 0 && bip.getWidth() == 0) {
     bip = child1.getBoundsInParent();

Might not be efficient (or pretty) but seems to work.

> Even if you do all these steps, calling setPrefWidth() on child2 marks
> the whole tree dirty again. Because HBox needs to resize child2 using
> it's new PrefWidth. This also means, HBox prefwidth will be different,
> so it's parent (VBox) must do the same. Ditto with the control. Also,
> the HBox (VBox, control) may not have enough size to resize child2 to
> it's pref width, so child1 might be shrinked as a result, which breaks
> your invariant. You are basically changing the input for HBox's layout
> (child2.pref size) based on it's output (child1 size), which makes this
> a loop.

Makes sense.

> So in order to really make this work, you need to manage the child nodes
> directly and compute your layout by yourself. This can be done either by
> using your own subclass of Pane and overriding it's layoutChildren. Or
> if you want to do everything in Skin's layoutChildren, you can make the
> children unmanaged, but then it doesn't really matter where they are in
> the scenegraph, HBox won't be managing them.
> Hope this helps!

It sure does. I have created pane-based controls with manual layouting 
before but it is some work to get it right, especially with the 
computeMinPrefMaxWidthHeight methods (sometimes +baseline), snapsize etc 
pp. I figured it is not worth the hassle here if a vbox and hbox do 95% 
of what I need :)  A cleaner approach would be to make child2 unmanaged 
as you suggest but then I need to reserve vertical space in its vbox 
container, currently done with css padding on the region itself. For the 
time being I have to stick with this and move on.

Thanks again.


More information about the openjfx-dev mailing list