JavaFX 1.3: Taming the Layout Beast

In the midst of celebrating JavaFX 1.3‘s performance improvements and CSS-stylable controls, let’s not forget about changes aimed to tame the beast we call “layout”.   My JavaFX 1.2 layout blog covered the fundamentals of bridging our declarative, animating scene-graph with traditional GUI layout and here I’ll follow up with some layout guidelines and a series of blogs describing how the changes we made in 1.3 are expressly intended to make your life easier, even if at first, being human, you feel a little resistant to change.

Most of the core concepts in JavaFX layout (logical vs. visual bounds, resizable vs not, use of binding vs. containers) remain complex and there’s no getting around spending  time to understand them (not unlike 2D or CSS).   But the 1.3 API changes should make it easier to get better dynamic layout with less code and fuss and here I’ve rewritten my layout guidelines to take into account 1.3 and another year’s worth of experience in constructing apps:

  1. Use the Container classes (HBox, VBox, Stack, Flow, Tile, *Grid (preview))  (rather than binding or static layout) whenever possible, as they handle the complexities of dynamic scene-graph layout for you.
    1. If you need something custom, consider writing your own Container subclass with a procedural doLayout function rather than a bunch of complex binding expressions.
    2. Remember that containers lay out children regardless of their visibility bit, so if you don’t want an invisible child to be layed out, then bind managed to visible.
    3. Use of LayoutInfo to customize the layout of a node inside a container should be the exception rather than the rule, as in 1.3 containers and controls have more natural layout default behaviors.
  2. For Resizable nodes (Containers & Controls), do not set their width/height vars directly, as all parent types now automatically set those values (usually to the resizable’s preferred size) during layout.  If you need to directly control the size of a node, override it’s preferred size using LayoutInfo.
  3. For non-Resizable nodes (Shape, Text, ImageView) you are responsible for establishing their size by setting the appropriate geometric or content variables.
  4. When arranging nodes directly inside a Group, CustomNode, or Scene (vs. Container) follow these guidelines:
    1. position child nodes by setting layoutX/layoutY, leaving translateX/translateY for adjustments and animation.  Remember that these are offsets, so always use the formula:
      layoutX: bind finalx - node.layoutBounds.minX
      layoutY: bind finaly - node.layoutBounds.minY.
    2. Use binding to establish dynamic behavior, but be careful not to create circular dependencies.
  5. Use layoutBounds as the basis of all layout-related calculations and understand that it may not correspond to the node’s visual bounds on the screen:
    1. a Resizable’s layoutBounds will always be 0,0 width x height
    2. a shape’s layoutBounds will be the bounds required to enclose their geometry (including stroke), but does not include effects, clip, or transforms.
    3. a Text node’s layoutBounds are now the logical bounds based on the font’s height and the content width, including any white space (in 1.2 it was the tight visual bounds around the characters, excluding whitespace).
    4. A Group’s layoutBounds is the union of the visual bounds (boundsInParent) of all its children.
    5. if you want a node’s effect, clip, or transforms (or any animation Timeline or Transition thereof) to be factored into its layout, then wrap it in a Group.

And finally, I’ve rewritten almost all of the layout related documentation in 1.3, so take a look and send me feedback.  I’m still wrestling this beast to the ground.

* we reserve the right to change preview APIs when we move them into core and already anticipate changes to Grid to support more dynamic node placement.

About these ads
This entry was posted in Uncategorized. Bookmark the permalink.

11 Responses to JavaFX 1.3: Taming the Layout Beast

  1. Steven Herod says:

    Point 2, about LayoutBounds and preferred size has caused me some anguish/confusion.

    When offered a writable variable called height: or width: I assume that setting the value will set the height or width. Of course, it seems not to.

    Would it be better for these properties become read only? Or am I missing something?

    • Amy Fowler says:

      You’re not alone; we had many bugs filed as a result of this confusion. If we were designing the API with today’s insight I would consider making them read-only and have a setSize() function on Resizable. It would eliminate the temptation to set them in object literals, but of course that wouldn’t stop apps from calling setSize() and having the same problem. Such an API would also limit the ability to set width/height on unmanaged Resizables or use bind to establish the value (admittedly smaller use cases, but worth mentioning). Note that the javadoc is now very clear on the restrictions and I’m hoping that tools can ultimately guide the user to override preferred size rather than directly setting width/height. I don’t think I could get such a change through the compatibility police at this point.

      • Steven Herod says:

        If you can give me the phone number of the compatibility police, I can lobby them. :)

        I think JavaFX is still too young to let stuff like that creep in. Perhaps a compiler warning/runtime warning?

  2. Are mouse events now based on layout bounds or is it still the renderable region? I still remember the troubles with trying to scroll a list view with the mouse wheel

    • Amy Fowler says:

      We’ve added pickOnBounds:Boolean to Node, which defaults to false for everything except Text (now you will get mouse events on Text without having to click precisely within the shape of a character!). However, pickOnBounds works with visual bounds rather than layoutBounds, so I’m not sure your LiistView problem is solved (though ListView was also rewritten, so it might). Please try it out and let us know.

  3. gregor says:

    Pagelayout (pagelayout.sourceforge.net) has ‘tamed the beast’ for swing. JavaFX might benefit from its somewhat novel approach.

  4. Pingback: JavaFX links of the week, May 10 // JavaFX News, Demos and Insight // FX Experience

  5. Pingback: JavaFX 1.3 Layout // JavaFX News, Demos and Insight // FX Experience

  6. whitemiyu says:

    Thank you Ms. Amy fowler

  7. ihsan says:

    Hi amy,
    is there a problem in layout passes?
    I’ve coded a tabbed pane scroll control whose manage attribute is bound to visibility of the control. It sometimes shows itself when it should not, sometimes does not show. When I’ve printed boundsInLocal of the node on an on replace block it always works fine. I think there is a problem with lazy binding and layout process. Unfortunately, I haven’t got the source code (i have coded it at work. if i can, i will try to repeat the bug at home )
    The last post at the below link contains a video link which is related again to layout.
    http://forums.sun.com/thread.jspa?threadID=5444434

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s