Over a million developers have joined DZone.

Getting Decked: Another JavaFX Custom Node

· Java Zone

Discover how AppDynamics steps in to upgrade your performance game and prevent your enterprise from these top 10 Java performance problems, brought to you in partnership with AppDynamics.

In the Rolling Your Own JavaFX "Custom Nodes": A Graphical Menu Example post, I began showing you how to create your own UI controls in JavaFX.  I also said that the JFX Custom Nodes category has been started in this blog in which custom nodes that you and I create will be featured.

Today's example features a simple custom node, named DeckNode, that I developed as a way to store a set of Node instances and display one of these nodes at a time.  It is being used to augment the graphical menu example by showing the Node that pertains to a given menu button.  Note that the concept is very similar to the Java CardLayout, so I wouldn't be surprised to see a similar class appear in the javafx.scene.layout package at some point.  Just for grins, I provided the ability to specify a fade-in duration for the node being displayed.  Here's a screenshot of the example application, with one of the nodes in the "deck" being displayed as the splash page: 

Decknodeexample_5  

One of the goals of JavaFX is for graphics designers and developers to be able to work together effectively in creating great looking applications.  To demonstrate this, Mark Dingman (the User eXperience director at Malden Labs) created some graphical mock-ups for the fictitious CD application shown above.  Future blog posts will turn these mock-ups into functioning pages using a combination of UI controls from the JavaFX SDK and custom nodes that we create in this blog.  Here's an example mocked-up page in the form of a graphic that is being displayed as a result of pressing the Play button:

Decknodeexample_play

By the way, Malden Labs, under CTO Thom Theriault's technical leadership, has made a strong commitment to using JavaFX for some pretty exciting systems in the works.  Anyway, if you would like to try today's example out, click on this Java Web Start link, keeping in mind that you'll need at least JRE 5.  Also, installing Java SE 6 update 10 will give you faster deployment time.

Webstartsmall2

Here's the code for the DeckNode class, contained in a file named DeckNode.fx:

/*
* DeckNode.fx -
* A node that shows a deck of nodes one at a time.
*
* Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
* to demonstrate how to create custom nodes in JavaFX
*/

package com.javafxpert.custom_node;

import javafx.animation.*;
import javafx.lang.*;
import javafx.scene.*;

/**
* A node that shows a deck of nodes one at a time. When the
* visibleNodeId attribute is assigned a value, the Node whose
* id is the same as the name becomes visible. Note that the
* the id attribute of each Node must be assigned a unique name.
* This class also has an attribute in which a fade-in duration
* may be specified.
*/
public class DeckNode extends CustomNode {
/**
* A sequence that contains the Node instances in this "deck"
*/
public attribute content:Node[];

/**
* The id of the node that is to be visible
*/
public attribute visibleNodeId on replace {
var nodes = for (node in content where node.id == visibleNodeId) node;
visibleNodeRef = if (sizeof nodes > 0) nodes[0] else null;
fadeTimeline.start();
}

/**
* The amount of time to fade-in the new Node
*/
public attribute fadeInDur:Duration = 1ms;

/**
* This attribute is interpolated by a Timeline, and the opacity
* attribute of this DeckNode class is bound to it. This helps
* enable the fade-in effect.
*/
private attribute opa:Number;

/**
* Override the opacity attribute so that it can be bound to the
* opa attribute that is interpolated by a Timeline
*/
override attribute opacity = bind opa;

/**
* A Timeline to control the fade-in behavior
*/
private attribute fadeTimeline =
Timeline {
keyFrames: [
KeyFrame {
time: bind fadeInDur
values: [
opa => 1.0 tween Interpolator.LINEAR,
]
}
]
};

/**
* A reference to the Node in the Node instances that is visible
*/
private attribute visibleNodeRef:Node;

/**
* Create the Node
*/
public function create():Node {
Group {
content: bind visibleNodeRef
};
}
}

Shown below is the main script for this program, in a file named DeckNodeExampleMain.fx:

/*
* DeckNodeExampleMain.fx -
* An example of using the DeckNode custom node. It also demostrates
* the MenuNode and ButtonNode custom nodes
*
* Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
* to demonstrate how to create custom nodes in JavaFX
*/
package com.javafxpert.deck_node_example.ui;

import javafx.application.*;
import javafx.scene.*;
import javafx.scene.geometry.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
import javafx.scene.transform.*;
import java.lang.System;
import com.javafxpert.custom_node.*;

var deckRef:DeckNode;

Frame {
var stageRef:Stage;
var menuRef:MenuNode;
title: "DeckNode Example"
width: 500
height: 400
visible: true
stage:
stageRef = Stage {
fill: Color.BLACK
content: [
deckRef = DeckNode {
fadeInDur: 700ms
content: [
Group {
var vboxRef:VBox;
var splashFont =
Font {
name: "Sans serif"
style: FontStyle.BOLD
size: 12
};
id: "Splash"
content: [
ImageView {
image:
Image {
url: "{__DIR__}images/splashpage.png"
}
},
vboxRef = VBox {
translateX: bind stageRef.width - vboxRef.getWidth() - 10
translateY: 215
spacing: 1
content: [
Text {
content: "A Fictitious Audio Application that Demonstrates"
fill: Color.WHITE
font: splashFont
},
Text {
content: "Creating JavaFX Custom Nodes"
fill: Color.WHITE
font: splashFont
},
Text {
content: "Application Developer: Jim Weaver"
fill: Color.WHITE
font: splashFont
},
Text {
content: "Graphics Designer: Mark Dingman"
fill: Color.WHITE
font: splashFont
},
]
}
]
},
Group {
id: "Play"
content: [
ImageView {
image:
Image {
url: "{__DIR__}images/playlist.png"
}
}
]
},
Group {
id: "Burn"
content: [
ImageView {
image:
Image {
url: "{__DIR__}images/burning.png"
}
}
]
},
Group {
id: "Config"
content: [
ImageView {
image:
Image {
url: "{__DIR__}images/config.png"
}
}
]
},
Group {
id: "Help"
content: [
ImageView {
image:
Image {
url: "{__DIR__}images/help.png"
}
}
]
}
]
},
menuRef = MenuNode {
translateX: bind stageRef.width / 2 - menuRef.getWidth() / 2
translateY: bind stageRef.height - menuRef.getHeight()
buttons: [
ButtonNode {
title: "Play"
imageURL: "{__DIR__}icons/play.png"
action:
function():Void {
deckRef.visibleNodeId = "Play";
}
},
ButtonNode {
title: "Burn"
imageURL: "{__DIR__}icons/burn.png"
action:
function():Void {
deckRef.visibleNodeId = "Burn";
}
},
ButtonNode {
title: "Config"
imageURL: "{__DIR__}icons/config.png"
action:
function():Void {
deckRef.visibleNodeId = "Config";
}
},
ButtonNode {
title: "Help"
imageURL: "{__DIR__}icons/help.png"
action:
function():Void {
deckRef.visibleNodeId = "Help";
}
},
]
}
]
}
}

deckRef.visibleNodeId = "Splash";

 

Please notice the last line of the listing above is what causes the node that we named "Splash" to be displayed when the application starts. 

The code for the other custom nodes used in this program (ButtonNode.fx and MenuNode.fx) are in the Rolling Your Own JavaFX "Custom Nodes": A Graphical Menu Example post, so you may want to visit that post.  At some point I'll put these custom nodes in a JAR file if developers find them useful.  As always, please leave a comment if you have any questions of comments!

Thanks,
Jim Weaver

The Java Zone is brought to you in partnership with AppDynamics. AppDynamics helps you gain the fundamentals behind application performance, and implement best practices so you can proactively analyze and act on performance problems as they arise, and more specifically with your Java applications. Start a Free Trial.

Topics:

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}