I created some simple diagrams for this blog post:

https://blogs.oracle.com/jfxprg/entry/the_peculiarities_of_javafx_layout

-Martin

On 07/29/2014 03:15 PM, Mikael Grev wrote:
Richard,

Is there a sequence diagram (or similar) where the layout process is described 
in detail?
It’s hard to in text get a clear and precise view on how the layout process in 
the Node hierarchy is happening.

The sequence diagram would be good to have as a constraint for building layout 
panes. Otherwise its easy to time things incorrectly with strange layout 
artefacts as a result.
It’s especially important for devs to know which methods are called for the 
pre-layout (size measuring) phase and them for the actual layout phase.

Cheers,
Mikael

On 28 Jul 2014, at 07:38, Martin Sladecek <martin.slade...@oracle.com> 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.

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.

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!

-Martin


On 25.7.2014 18:56, Richard Bair wrote:
Hmmm. The first question I have is whether boundsInParent is really what you 
want to use, vs. layout bounds. But assuming it is what you want, why are the 
bounds zero? This is during the layout pass, which is the right place to be 
doing what you’re doing. The super layoutChildren call will size everything 
based on the contentX, contentY, contentWidth, contentHeight 
(http://hg.openjdk.java.net/openjfx/8u-dev/rt/file/4b8d06211312/modules/controls/src/main/java/javafx/scene/control/SkinBase.java).
 Is it possible that the parent itself is size 0? boundsInParent should always 
be invalidated automatically whenever the width/height/transforms/etc changes. 
If not that is definitely a bug (that you can write a simple test case for to 
prove).

But my first guess is maybe the parent is size 0 as well, due to something else 
(maybe the pref size of the control is 0 to start with or something…)

Richard

On Jul 24, 2014, at 3:34 AM, Werner Lehmann <lehm...@media-interactive.de> 
wrote:

Hi,

inside a control skin I have the following code pattern:

  protected void layoutChildren(...)
  {
    super.layoutChildren(...);

    Node child1 = ...
    Bounds bip = child1.getBoundsInParent();

    if (!animating) {
      Node child2 = ...
      child2.setTranslateX(bip.getMinX();
      child2.setPrefWidth(bip.getWidth());
    }
  }

The skin scene graph looks roughly like this:

VBox
  HBox { ..., child1, ...}
  child2
  ...

Everything is layouted just fine but I want to adjust child2.translateX and 
prefWidth based child1 bounds. This does not work initially because 
boundsInParent returns zero components leading to incorrect initial display of 
the control.

Seems as if boundsInParent is not yet updated. I guess I could use a binding 
for that but it would conflict with an animation I also have on translateX and 
prefWidth.

Maybe there is a better time to make those adjustments on child2?

Rgds
Werner

Reply via email to