Martin,

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

http://postimg.org/image/t9a6esc71/

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) {
    vbox.layout();
    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.

Werner

Reply via email to