
Potentially one of the most powerful parts of JavaFX 1.2, oft overlooked, is its ability to reach inside layered graphics files to manipulate their constituent parts. In this tutorial I'm going to show a very simple example of this; taking a layered SVG file and turning it into a dynamic element inside a JavaFX program.
Our SVG has two layers; by extracting them inside the JavaFX Script code, then adding event handling code to one of them, we're going to create a simple slider control (see figure 1).

Before we can write any code we need a graphic to play with. I'm going to use Inkscape to create an SVG (Scalable Vector Graphics) file, although you could just as easily use Adobe Illustrator if you have access to it (or Photoshop if you prefer a bitmap format rather than a vector format). The image consists of two parts: the shaft is the line (grey in figure 2) that shows the horizontal range of the control, and the thumb (smiley in figure 2) is the part users can drag along the shaft.
Each part of the image is created on a separate layer and tagged with
special IDs; jfx:shaft for the shaft and jfx:thumb
for the thumb. The jfx: prefix is an indicator to the
SVG to FXD convertor tool that ships as part of JavaFX's Productivity
Suite. Having saved our SVG file in Inkscape we need to run this tool
to convert the data into JavaFX's own data format (FXD). The prefix
tells the tool to preserve those IDs in the FXD data it outputs. This
will give us a means to reach inside the data and pluck out individual
layers once we've loaded the FXD into our JavaFX code.
(Note: to correctly set a layer ID in Inkscape you need to use the app's SVG XML editor. The layer names shown by the Inkscape user interface are human readable labels, not SVG node IDs.)
Once the tool is run, and the FXD is created, we can move on to the most important part of this tutorial: extracting the layers and adding the necessary event handlers.
The file the SVG to FXD convertor outputs will probably be a zipped
file with an FXZ extension. This file needs to be placed in our
build environment so that it will appear inside the tutorial2
package when the code is compiled — this is the package the code
lives in, and where it looks for its resource files.
The code is fairly short and sweet, less than 60 lines. You can see it running in figure 3, and the code is in listing 1 below.
package tutorial2;
import javafx.fxd.FXDNode;
import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
Stage {
scene: Scene {
content: [
Slider{ layoutX: 10; layoutY: 10; }
]
width: 320; height: 70;
}
}
class Slider extends CustomNode {
var shaft:Node;
var thumb:Node;
var dragStartX:Number;
override function create() : Node {
// Load FXZ file, extract component nodes
def fxd:FXDNode = FXDNode {
url: "{__DIR__}slider.fxz";
backgroundLoading: false;
}
shaft = fxd.getNode("shaft");
thumb = fxd.getNode("thumb");
// Assign event handlers, to make thumb draggable
thumb.onMousePressed = mouseDown;
thumb.onMouseDragged = mouseDrag;
// This component's content is the FXD node
return fxd;
}
function mouseDown(ev:MouseEvent) : Void {
dragStartX = thumb.layoutX;
}
function mouseDrag(ev:MouseEvent) : Void {
var x:Number = dragStartX + ev.dragX;
def min = shaft.layoutBounds.minX;
def max = shaft.layoutBounds.maxX-thumb.layoutBounds.width;
if(x < min) {
x = min;
}
else if(x > max) {
x = max;
}
thumb.layoutX = x;
}
}
The most important part of the code is in the Slider class,
which is a CustomNode subclass. The create()
function sets the scene graph up. First it loads the slider.fxz
file as a FXDNode (see red
highlight). This is a special type of scene graph node that can be
created from FXD/FXZ data. When loaded, the shaft and thumb layers will
be created as children inside the FXDNode. The next step,
therefore, is to extract those child nodes into variables so we can
more readily manipulate them. Because the parts of the image we wanted
to manipulate were tagged with a jfx: prefix in the original
SVG, we can pull them out by name in the JavaFX Script code.
The nodes we pull out of the FXD data are real JavaFX scene graph nodes,
and can be manipulated like any other node. This includes adding event
handlers, as the green highlighted
code shows. The code adds two handlers to thumb: one for
when the mouse button is pressed, and one for when the mouse is dragged.
The event handlers are quite simple. When the mouse is pressed its X
location is stored, and when it is dragged the thumb node
is moved accordingly. The blue
highlighted code restrains the thumb inside the bounds of
the shaft.
Obviously this is only a simple example, but it shows the power of what is possible when JavaFX Script is used in conjunction with the JavaFX Production Suite. A graphic designer can modify the original image, create a fresh FXD/FXZ file from it, then drop it straight into the JavaFX project. — providing the necessary layers are tagged with the right IDs the code can reach inside the data, pull out the bits it needs, and bring them to life.
Source code (4k) |

