Define constants and variables
Step 1: Define constants and variables
in the custom layout. You want the PlayingCardLayout class to be able to support three different layout arrangements, so define three constants to do the job:
public def VERTICAL_ARRANGEMENT:Integer = 0; public def HORIZONTAL_ ARRANGEMENT:Integer = 1; public def FAN_ARRANGEMENT:Integer = 2;
If you’re working through the code for PlayingCardLayoutA, add the FAN_ARRANGEMENT definition to your PlayingCardLayout.fx script under the existing VERTICAL_ARRANGEMENT and HORIZONTAL_ARRANGEMENT statements.
In the body of the PlayingCardLayout
package playingcard.ui; import javafx.scene.*; import javafx.scene.input.*;
public class PlayingCard extends CustomNode {
public var node:Node; override public var blocksMouse = true; override var children = Group {
content: bind node // Demonstrate the results of unmanaging a node onMousePressed: function(me:MouseEvent):Void {
managed = false; toFront();
} onMouseReleased: function(me:MouseEvent):Void {
managed = true;
Code Listing 1: PlayingCard.fx script—class definition for PlayingCard nodes
class definition is a public instance variable,
Code Listing 2: PlayingCardMain.fx script
arrangementStyle, whose definition includes
a replace trigger that automatically runs
/* PlayingCardMain.fx - to demonstrate PlayingCardLayout custom layout */
whenever the value of the variable changes:
package playingcard.ui;
public var arrangementStyle:Integer =
import javafx.stage.Stage;
VERTICAL_ARRANGEMENT on replace {
import javafx.scene.Scene;
preferredDirty(true);
import javafx.scene.image.*; import javafx.scene.layout.*;
requestLayout();
import playingcard.layout.PlayingCardLayout;
The variable is initialized with the
var firstPile:PlayingCard[] = for (i in [1..10])
VERTICAL_ARRANGEMENT constant, but PlayingCard {
node: ImageView {
the associated trigger is activated whenever
image: Image {
this variable value changes, setting the
url: "{__DIR__}images/{i}.png"
preferredDirty variable to true and calling
the requestLayout() function, another
Container class function. (As you’ll discover in subsequent steps, the preferredDirty
var secondPile:PlayingCard[] = for (i in [11..24])
PlayingCard {
variable acts as a flag throughout the
node: ImageView {
PlayingCardLayout code.)
image: Image {
The requestLayout() function tells the
url: "{__DIR__}images/{i}.png"
JavaFX runtime to make a layout pass run
before rendering the next scene. This trig-
gering mechanism, in conjunction with code in the doLayout() function, facilitates var thirdPile:PlayingCard[] = for (i in [25..54])
PlayingCard {
the rendering of the three layouts.
node: ImageView {
Note that the content variable is being
image: Image {
overridden, also through use of a replace url: "{__DIR__}images/{i}.png"
trigger. Each time the designated layout
(horizontal, vertical, or fan-shaped) changes,
the value of the variable changes.
Stage {
var sceneRef:Scene;
override var content on replace {
title: "PlayingCardLayout Example" scene: sceneRef = Scene {
preferredDirty = true;
width: 600
height: 400 content: [
All layout managers have a content HBox {
layoutX: 20
instance variable, inherited from the
layoutY: 20
Container class, whose purpose is to
spacing: 20
be assigned a sequence of nodes to be
content: [
PlayingCardLayout {
managed. The custom layout class uses this
arrangementStyle: PlayingCardLayout.VERTICAL_ARRANGEMENT
variable in the overridden doLayout() func-
content: firstPile
tion in a subsequent step.
}, PlayingCardLayout {
The calcPreferredSize() function is a
arrangementStyle: PlayingCardLayout.HORIZONTAL_ARRANGEMENT
helper function in PlayingCardLayout that
content: secondPile
calculates the preferred width and height
for the nodes it is processing for the calling PlayingCardLayout {
arrangementStyle: PlayingCardLayout.FAN_ARRANGEMENT
function and returns the dimensions that
content: thirdPile
will be required for the layout. When it’s
finished, the function sets the value of the ]
preferredDirty variable to false. If you’re
working through the example, add the fol-
lowing code to the calcPreferredSize() func- }
NOVEMBER/DECEMBER 2010 ORACLE.COM/ORACLEMAGAzINE NOVEMBER/DECEMBER 2010 ORACLE.COM/ORACLEMAGAzINE
documentation (download.oracle.com/ for the fan-shaped layout:
if (arrangementStyle == VERTICAL_
ARRANGEMENT) {
docs/cd/E17802_01/javafx/javafx/1.3/
docs/api) for complete details. else { // arrangementStyle == FAN_
for (node in getManaged(content)) {
• getNodePrefWidth() —determines the pre- ARRANGEMENT
layoutNode(node, 0,
ferred width of a node. preferredWidth = Math.sqrt(
indexof node * verticalOffset,
• getNodePrefHeight() —determines the pre- Math.pow(lastNodeWidth, 2) +
getNodePrefWidth(node),
ferred height of a node. Math.pow(lastNodeHeight, 2)) * 2;
getNodePrefHeight(node));
The online version of this article, at oracle preferredHeight = preferredWidth;
.com/technetwork/issue-archive/2010/ }
else if (arrangementStyle ==
10-nov/o60javafx-170536.html, concludes
with information on force recalculation And be sure to also change the ELSE for
HORIZONTAL_ARRANGEMENT) {
of the containing layout manager’s the arrangementStyle == HORIZONTAL_
for (node in getManaged(content)) {
width and height and how to modify the ARRANGEMENT statement to an ELSE IF for
layoutNode(node,
PlayingCardMain.fx script. proper syntax.
indexof node * horizontalOffset,
Step 2: Override the doLayout() function.
getNodePrefWidth(node),
CONCLUSION
The doLayout() function contains the rules
JavaFX includes several built-in layout man- for how nodes should be laid out. For the
getNodePrefHeight(node));
agers, but occasionally they don’t meet the example projects, the overridden doLayout()
requirements of an application. When this function iterates over the managed nodes
happens, consider creating your own, fol- and affects their sizes and positions.
else if (arrangementStyle ==
FAN_ARRANGEMENT) {
lowing the steps detailed in this article.
def startAngle = (sizeof
override function doLayout():Void {
getManaged(content)) * -0.5 * fanAngle;
James L. Weaver has been a developer
if (preferredDirty) {
for (node in getManaged(content)) {
for more than 25 years. since 2000 he has
calcPreferredSize();
def rot = Rotate.rotate(
specialized in Java, object-oriented, and Web-
startAngle + (indexof node *
based technologies. He is the author of Pro
JavaFX Platform: Script, Desktop and Mobile When the JavaFX runtime calls the
fanAngle), 0,
RIA with Java Technology (Apress, 2009) and doLayout() function, it first determines
node.layoutBounds.height);
JavaFX Script: Dynamic Java Scripting for Rich if the arrangement of a layout manager’s
delete node.transforms;
Internet/Client-Side Applications (Apress, 2007). nodes should be re-evaluated by checking
insert rot into node.transforms;
var ph = getNodePrefHeight(node);
the value of the preferredDirty variable.
var pw = getNodePrefWidth(node);
NEXT STEpS
When preferredDirty is set to true,
layoutNode(node, ph, pw, pw, pw);
doLayout() calls the calcPreferredSize()
DOWNLOAD the sample code for
helper function to calculate the width and
this article
the height based on the arrangement style,
oracle.com/technetwork/issue-archive/ size, and number of cards to be arranged, 2010/10-nov/o60javafx-168643.zip
READ as well as the offset value. online-only article content Within the overridden doLayout() func- oracle.com/technetwork/issue-archive/ The calcPreferredSize() function returns
2010/10-nov/o60javafx-170536.html these values for the card stack in question
tion are several convenience functions (from
Container) for managing nodes:
READ more technical articles about JavaFX
oracle.com/technetwork/java/ to false, so that when the processing control index-141532.html#javafx (sequence) of nodes being managed
and then resets the preferredDirty variable
• getManaged() —returns the group
returns back to the calling function (in this “Building GUI Applications With JavaFX” by the container—that is, those nodes download.oracle.com/javafx/1.3/tutorials/ui case, doLayout()), the returned values will be
whose managed instance variable is true.
“Learning the JavaFX Script programming
handled by the appropriate IF statement in
By default, all nodes are created with the
Language”
the function. In other words, the playing card
download.oracle.com/javafx/1.3/tutorials/core will be positioned properly within its desig-
default value, but if you want a node to
be exempt from the policies of the layout
LEARN how to get started with NetBeans IDE
nated arrangement (horizontal, vertical, or 6.9 for JavaFX manager, set its managed variable to false. download.oracle.com/javafx/1.3/getstarted fan-shaped).
• layoutNode() —sets the position of a node
more about the JavaFX 1.3.1 ApI
and attempts to resize it. This is an over-
download.oracle.com/docs/cd/E17802_01/
DOWNLOAD the JavaFX 1.3.1 ApI and
loaded function that has several variations
javafx/javafx/1.3/docs/api
NetBeans IDE 6.9.1 VISIT the JavaFX resources site
from which you can choose, depending on your needs. Check the JavaFX API reference oracle.com/technetwork/java/javafx/overview
javafx.com/downloads/all.jsp
ORACLE MAGAzINE NOVEMBER/DECEMBER 2010
Create cutting edge reports with the complete set of
tools from Altova ®
Experience how the Altova MissionKit ® , the integrated suite of XML, database, and data integration tools, lets you display and analyze data through enhanced chart and report generation.
Report generation is finally easy – and affordable – with Altova MissionKit reporting tools:
StyleVision ® – stylesheet and report design tool • Consolidated reporting based on XML,
database and/or XBRL data • Dynamic data selection and rendering • HTML, Microsoft Word, PDF, and e-Form report creation
New in XMLSpy ® – advanced XML editor Version 2011:
• Instant creation of charts to analyze XML data
Ground-breaking
• One-click export of charts to XSLT, XQuery, or image files
support for chart creation
MapForce ® – any-to-any data mapping tool
• Integration with StyleVision for rendering attractive reports • Report generation for virtually any data format:
XML, databases, EDI, flat files, Excel 2007+, and more
Download a 30 day free trial!