Skin layoutChildren: when to get bounds of child nodes?
Werner Lehmann
lehmann at media-interactive.de
Wed Jul 30 15:12:16 UTC 2014
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
More information about the openjfx-dev
mailing list