Creating a JavaFX Design Without Programming
14 Jan 2009
There are already numerous tutorials that show you how to develop JavaFX user interfaces programatically. Many of the tutorials on Sun's own site show you how to build your UIs programatically. I would like to show you another option available to JavaFX developers: the JavaFX Production Suite (aka Project Nile). Project Nile is a suite of tools capable of exporting to JavaFX native format from Adobe Illustrator, Photoshop or any software capable of creating SVG illustrations. To demonstrate the power of the Production Suite, I'm going to show you how to create a button component. The interesting part about this button is that the design will be produced entirely in an SVG design tool. We will use JavaFX to only manage the state of the button and control its behavior.
Downloading The Source
If you would just like to play around with a working sample button project, you can download the complete source from GitHub. If you’re unfamiliar with git, there’s a direct download link on the GitHub project page. The rest of the tutorial will show you how the project was put together.
Before Starting
Before you start to follow along, please be sure you have the following installed on your computer:
- NetBeans 6.5 with JavaFX 1.0
- The JavaFX Production Suite 1.0
- (optionally) InkScape. An open-source vector illustration application that uses SVG as its native format. Though any tool that produces SVG files should suffice. You won’t need InkScape to setup and run the sample application we build.
Once you have the required software, create a new project in NetBeans called: Button. Choose a default package for your project. This tutorial assumes you’ve chosen net.newfoo.button for your package. To add production suite capabilities to your project, you’ll also need to JavaFX FXD 1.0 library to your Library list.
Working With the Design
The design we receive should provide 4 different views for each state of the button: normal, hovered, pressed and disabled. The code behind our button will simply ensure that only the correct button state is showing at any given time. In order to simplify our event handling, we should also have a graphical element available in our design that can capture all mouse events. In our design, we’re going to place another graphical element below all other elements for this purpose. The element will always be visible, but obscured by the active button state. This allows us to capture our mouse events. All five elements should be stacked on top of each other in this order: active area, disabled, pressed, hovered, normal. These elements should be placed in a group called: button.

You should save the SVG asset in our project folder in a file called /art/button.svg. If you don’t want to work with the button in an SVG editor, you can simply download the file to your project.
Converting to JavaFX
Once the design has been saved to /art/button.svg, we need to convert it to a format consumable by our JavaFX code. Open the SVG Converter program in the Production Suite. Locate your button asset in SVG format using browse button in the Source File (.svg) field. To populate the Destination File (.fxz) field, click the browse button and navigate to /src/net/newfoo/button. Type button.fxz in the Save As field. Click on the Convert button.
In your Button project in NetBeans, you should now see a button.fxz file under Source Files/net/newfoo/button. We’re going to create a UI Stub, a bridge between this asset file and our application, that makes it easier to work the different layers of our design. You can generate your UI stub, by right-clicking on the button.fxz file and selecting “Generate UI Stub…” When prompted, you should name your stub, “ButtonUI.fx.”
Once the the ButtonUI Stub has been created, open it in your editor and make the following changes:
- import javafx.scene.Group
- Change the line
public var button: Nodetopublic var button: Group. - Change the line
button=getNode("button")tobutton=getGroup("button")
These changes make it a little easier to define some re-usable JavaFX code to model the button’s state. After making that change to the stub we’re able to use any button asset in a file called button.fxz as long as it conforms the same layer structure as our original button. In a larger application, the stub will often provide a gateway to all graphical assets of the application.
Writing the Button Code
With a little effort we can develop a generic button control that places minimal restrictions on how the graphic assets should be defined. Our button has placed the constraint that the asset should be a group of nodes called “button” and that it should have 5 items in this order: the active area and the disabled state, pressed, hovered and normal states. These two constraints allow us to develop a re-usable JavaFX class that can be used for any button in our application! Without further ado, let’s create a new JavaFX class in our NetBeans project called Button. Here is the code you should place in there:
package net.newfoo.button;
import javafx.scene.CustomNode;
import javafx.scene.input.MouseEvent;
import javafx.scene.Node;
import javafx.scene.Group;
import javafx.scene.text.Text;
public class Button {
public-init var group : Group on replace {
normal = group.content[4];
hovered = group.content[3];
pressed = group.content[2];
disabled = group.content[1];
activeArea = group.content[0];
}
public-init var pressed : Node;
public-init var hovered : Node;
public-init var normal : Node;
public-init var disabled : Node;
public-init var activeArea : Node;
public var action : function ():Void;
public var disable = false on replace {
activeArea.disable = disable;
if (disable) {
isPressed = isHovered = false;
normal.visible = hovered.visible = pressed.visible = false;
} else {
normal.visible = hovered.visible = pressed.visible = true;
}
}
var isPressed : Boolean on replace {
updateUI ();
}
var isHovered : Boolean on replace {
updateUI ();
}
init {
if (activeArea != null) {
activeArea.onMouseEntered = function (e) {
if (not disable) {
isHovered = true;
}
}
activeArea.onMouseExited = function (e) {
if (not disable) {
isHovered = false;
}
}
activeArea.onMousePressed = function (e) {
if (not disable) {
isPressed = true;
}
}
activeArea.onMouseReleased = function (e) {
if (not disable) {
isPressed = false;
action();
}
}
}
isPressed = false;
isHovered = false;
updateUI ();
}
function updateUI () {
if (pressed != null)
pressed.visible = isPressed;
if (hovered != null)
hovered.visible = not isPressed and isHovered;
if (hovered != null)
normal.visible = not isPressed and not isHovered;
}
}
Putting It All Together
Now that you’ve designed the button and written the code to control the button behavior, we need to put it all together and make a running application. To link everything together we’ll write a simple JavaFX stage:
package net.newfoo.button;
import javafx.stage.Stage;
import javafx.scene.Scene;
var buttonUI : ButtonUI = ButtonUI{ }
var button = Button{ group: buttonUI.button };
Stage {
title: "My Button"
width: 300
height: 300
scene: Scene {
content: button.group
}
}
Lines 6 & 7 in the above example are the only code that’s needed to bind our designer’s vision for the button to our generic button code. The designer is now free to update the design as he/she sees fit. As long as the designer sticks to our 2 constraints, the button should have 5 layers and be placed inside a group called “button”, our button will work no matter how fancy the design becomes.
Final Thoughts
This tutorial only scratches the surface of the JavaFX Production Suite’s capabilities. Using the steps outlined above, you can create an entire application using this method. The button code above can be used to generically control any kind of button regardless of the button’s look and feel.
Unlike many of the other multimedia platforms, you can create your applications without tedious design handoffs or expensive design tools. All of the tools used to create this design were either free or open source. With a few conventions and proper project setup, you can completely automate design updates. In a future post I’m going to demonstrate how to leverage the production suite to build a fully working game.
To find out more information about the Production Suite you should visit Sun’s Getting Started page. The page has helpful information for designers using Adobe tools to create design assets. You can also see working examples leveraging the Production Suite in your Samples folder under your Production Suite installation directory.