JavaFX Production Suite Graphics for Developers

Learn how Production Suite facilitates the designer-developer workflow and how developers can integrate graphics exported from Production Suite into their JavaFX applications.

JavaFX Production Suite is a set of tools that helps visual designers work more efficiently with developers to incorporate rich graphic assets into JavaFX applications. Using Production Suite, designers can convert graphics to JavaFX format, which developers can incorporate in their JavaFX applications.

15 Puzzle

What Is JavaFX Graphic Format?

When a graphic is converted to JavaFX format, a compressed archive file is produced with an FXZ extension. This compressed file can be uncompressed with any zipping utility and contains the following files:

  • At least one content file with an FXD extension. FXD format is a textual description of the graphic and follows the FXD specification. FXD elements map directly to JavaFX API classes.

  • Embedded assets, such as image files or TrueType fonts, depending on the options selected during export. All embedded assets are referenced in the FXD description.

These features of JavaFX graphic format make these images highly compatible with JavaFX applications.

How JavaFX Production Suite Enhances the Design-Developer Workflow

If you have collaborated with a designer to create an application with rich graphic assets, you are familiar with the iterative and sometimes tedious collaboration required. A typical designer-developer workflow is shown in Figure 1. The designers are focused on creating beautiful and effective user experiences, while the developer is focused on making the application function. Designers usually deliver a large set of image files, each containing a single graphic object or other asset that you need for your application. You have to track the individual assets, and every time there is a change, you must go through the process again. New assets often result in new code.

Collaborative Context for Applications with Rich Graphic Assets Figure 1: Collaborative Context for Applications with Rich Graphic Assets

JavaFX Production Suite was designed from the ground up to support the designer-developer workflow in the following ways:

  • It enables designers to work with their tools of choice to create compelling visuals.
  • It simplifies the process of importing graphic objects into JavaFX Script applications.
  • It enables developers to manipulate individual graphic objects within a visual asset.
  • It enables developers to drop in new versions of visual assets with minimal change to the code.

For an example of the designer-developer workflow in developing an application based on a JavaFX graphic exported by using Production Suite, see the article Getting Started with JavaFX Production Suite.

Here are some specific advantages of using JavaFX graphics in your JavaFX applications.

Extract Graphic Objects From a Single Application UI

Designers can deliver a single application UI, and you can use JavaFX APIs to load and manipulate individual graphic objects (groups, layers, and some effects) in your JavaFX application. This saves time for both you and the designer in not having to manage a large number of asset files. The application for the following applet, described in another section of this article, is based on a single Photoshop file.

How this works: When graphics files are converted to JavaFX graphic format, JavaFX graphic objects are created that match the layers in the original artwork. These graphic objects are loaded into the JavaFX application as nodes, which enables you to treat them as you would other nodes in JavaFX Script.

In the case of Photoshop artwork, individual layers are exported as individual PNG files in the FXZ archive, and an FXD description is created that describes each layer in an element, pointing to the PNG files as appropriate. Each element in the FXD description becomes a node when loaded into a JavaFX application. When Adobe Illustrator artwork is exported, most graphic objects are exported as FXD descriptions. Since FXD descriptions of all effects are not supported, there are several options for how to treat known and unknown effects, including rasterizing to PNG files.

Text layers have different options during export. Text layers in Photoshop can be converted to Text elements in the FXD description or rasterized as bitmaps. Text layers in Adobe Illustrator are converted to Text elements in the FXD description. When text is converted to Text elements, there is an additional option to embed the fonts as TrueType files in the FXZ archive.

Focus on the Graphic Objects You Need to Work With

JavaFX graphics can be created such that the graphic objects the developer plans to manipulate have a special status, enabling developers to focus on the items that are of more importance during application development.

How this works: The designer assigns a jfx prefix to the names of graphic objects that are of interest to developers. During the export process, the designer selects the option to assign IDs only to graphic objects with a jfx prefix. In the example application described in this article, the background is not manipulated programmatically in the application, so it does not have a jfx prefix in the original Adobe Photoshop artwork, as shown in Figure 2.

The 15 Puzzle in Adobe Illustrator Figure 2: Assign jfx Prefixes to Layers of Interest

The resulting FXD description assigns ID values to the objects with a jfx prefix, as follows.
FXD Description of the Original Photoshop Artwork
FXD {
content:
	Group {
		clip: Rectangle { x:0 y:0 width:527 height:602 }
		content: [
			ImageView {
				x: 6
				y: 3
				image: Image {
					url: "Background.png"
				}
			},
			ImageView {
				id: "Sun"
				x: 19
				y: 24
				image: Image {
					url: "Sun.png"
				}
			},
			ImageView {
				id: "Balloon"
				x: 304
				y: 49
				image: Image {
					url: "Balloon.png"
				}
			},
			ImageView {
				id: "Boat"
				x: 19
				y: 243
				image: Image {
					url: "Boat.png"
				}
			},
			ImageView {
				id: "Fish"
				x: 335
				y: 455
				image: Image {
					url: "Fish.png"
				}
			},
			ImageView {
				id: "Bubble"
				x: 262
				y: 427
				image: Image {
					url: "Bubble.png"
				}
			},
		]
	}
}

Minimize Recoding After Design Changes

Designers can make changes to the graphic objects while minimizing the impact on the application code.

How it works: If the names of the objects remain the same and the basic graphic object hierarchy remains intact, designers can often make changes to the design with minimal impact to the code. For example, Figure 3 shows an example in which the designer changed the position of the play, pause, and next buttons. The developer assigned mouse functions to the buttons but did not alter the location assigned to them in the original image, so the new graphic was dropped into the application and kept the same functionality with no change of code.

The 15 Puzzle in Adobe Illustrator Figure 3: Buttons Can Change Position Without Recoding

Changing the design without changing the application code is not possible in every case, but as designers and developers become more experienced in working together, designers learn how to make design changes that minimize the impact application code.


Give the Developer Some Control

Once you have loaded the JavaFX graphic into your JavaFX application, you can treat the individual graphic objects as you would individually loaded images or other nodes, assigning variables from the JavaFX API, or defining custom classes and custom functions for them in JavaFX Script. For example, you can apply transitions and transformation, add user interactivity, and even change text, as long as the text object is described with a Text element in the FXD description. This ability to manipulate graphic objects reduces the demand on the designer to produce images of the exact size and in the exact location in the UI, or to produce a series of graphics for transformations such as rotations and shearing.

For example, Figure 4 shows two stars developed in an SVG authoring tool on the left side, and the stars repositioned in the JavaFX application using the translateX variable.

The 15 Puzzle in Adobe Illustrator Figure 4 Reposition Objects After Loading Them

For the balloon object shown in the applet on this page and in Figure 2 a transformation such as shearing can be added with a single line of code:

The 15 Puzzle in Adobe Illustrator Figure 5 Balloon Object With a Shear Transformation Applied

Do Developers Need to Install Production Suite?

As a developer, you only need to install JavaFX Production Suite if you plan to do any of the following activities:

  • You plan to design graphics yourself in Adobe Illustrator, Adobe Photoshop, or an SVG graphics tool and need to export them to JavaFX format.

  • You want to view JavaFX graphic images that you receive from designers and you are working outside the NetBeans IDE, which has built-in capabilities to view JavaFX images and to edit and create FXD source descriptions.

  • You want to view the JavaFX Production Suite samples to see more examples of how to incorporate Production Suite graphics into your JavaFX application.

JavaFX Production Suite is a separately downloadable part of the JavaFX platform. It contains plugins to convert graphics from Adobe Illustrator and Photoshop to JavaFX format, a converter for SVG graphics, a viewer that displays the exported graphics, samples, and documentation. For a complete description of the JavaFX Production Suite tools and aids, see Installing JavaFX Production Suite. The NetBeans IDE for JavaFX comes with the capabilities to view and work with JavaFX graphics.

An Application that Uses a Production Suite Graphic

The application featured in the applet on this page is very similar to the application in the article Easy Animations With the Animated Transitions. In that article, each individual graphic is included as a resource and loaded separately into the application. In the application presented here, a single Photoshop image is exported as a JavaFX graphic, and JavaFX Script code is used to load the image and its individual objects, then the transitions are applied to each object using a custom function.

In the NetBeans IDE you can exploit a shortcut to loading JavaFX graphics by creating a UI stub file. UI stub files contain a custom class that extends the FXDNode class, declares a variable for each graphic object that has an ID value in the FXD description, and defines a function that loads the content for each node. For this application, the following UI stub file was generated:

Source Code: Contents of the UI Stub File Generated for the JavaFX Graphic balloonboatfish.fxz
import java.lang.*;
import javafx.scene.Node;
import javafx.fxd.FXDNode;

// Define a custom class that extends FXDNode
public class balloonboatfishUI extends FXDNode {
	
	override public var url = "{__DIR__}balloonboatfish.fxz";
	
   // Declare a variable for each FXD element with an ID value
	public-read protected var Balloon: Node;
	public-read protected var Boat: Node;
	public-read protected var Bubble: Node;
	public-read protected var Fish: Node;
	public-read protected var Sun: Node;
	
   // Function to load the graphic objects
	override protected function contentLoaded() : Void {
		Balloon=getNode("Balloon");
		Boat=getNode("Boat");
		Bubble=getNode("Bubble");
		Fish=getNode("Fish");
		Sun=getNode("Sun");
	}
	
	/**
	 * Check if some element with given id exists and write 
	 * a warning if the element could not be found.
	 * The whole method can be removed if such warning is not required.
	 */
	protected override function getObject( id:String) : Object {
		var obj = super.getObject(id);
		if ( obj == null) {
			System.err.println("WARNING: Element with id {id} not found in {url}");
		}
		return obj;
	}
}

In the JavaFX application, the UI stub file is listed in the imports, and a custom class defined in the UI stub file is assigned to a variable, as shown in the following JavaFX Script code.

Source Code: Loading the JavaFX Graphic
import pstransitions.res.balloonboatfishUI;

// Use a UI stub file to load the graphic
def psobj = balloonboatfishUI{};

There are other ways to load JavaFX graphics besides creating a UI stub file, and you can load them synchronously or asynchronously. For examples, see the Production Suite section of the how-to topic How do I work with images.

Once the graphics are loaded and assigned to nodes, the bubbles and the boat are scaled to 50% of their initial size by using the scaleX and scaleY variables inherited from the Node class. The boat is also repositioned by using the layoutX and layoutY variables. These changes are shown in the following source code snippet.

Source Code: Scale and Move Some Images With Inherited Node Variables
//Make the bubbles half size
psobj.Bubble.scaleX = 0.5;
psobj.Bubble.scaleY = 0.5;
//Make the boat half size and reposition it
psobj.Boat.scaleX = 0.5;
psobj.Boat.scaleY = 0.5;
psobj.Boat.layoutX = -20;
psobj.Boat.layoutY = 20;

To add the shear effect to the balloons shown in Figure 5, add the following line of code:

Source Code: Add a Shear Transformation to the Balloons
psobj.Balloon.transforms = Shear { x: -0.5 y: 0 }

In this application, all animations are created with transitions, which are various classes in the javafx.animation.transition package. For an explanation of the transitions, see the article Easy Animations With the Animated Transitions. All of the transitions are started and paused by clicking an object. A custom function is defined to get a particular node identified by its ID string, assign it to the node variable in the Transition class, and start and stop the transition, as shown in the following code.

Source Code: Custom Function for User Interactivity
// First, define the function parameters
function animateNode(root:FXDNode, id:String, transition:Transition) {
    // Get the correct node for the transition
    def node = root.getNode(id);
    transition.node = node;
    // Define the onMouseClicked function to play or pause the transition
    node.onMouseClicked = function(e){
        if (not transition.running or transition.paused) {
            transition.play();
        } else {
            transition.pause();
        }
    }
}

The custom function is then used to define the transition for each graphic object, as shown in the following code.

Source Code: Define the Transitions
// Make the sun grow dimmer and brighter
// Call the function and pass in the two parameters
animateNode(psobj, "Sun",
    FadeTransition {
        duration: 3s
        fromValue: 1.0 toValue: 0.0
        repeatCount: Timeline.INDEFINITE
        autoReverse: true
    }
);


//  Create a path for the boat
var path = Path {
    elements: [
        MoveTo {x: 130 y: 330},
        ArcTo { x: 440  y: 350
            radiusX:  350  radiusY: 80
            sweepFlag: true
        }
    ]
    stroke:Color.WHITE
}

// Move the boat along the defined path
animateNode(psobj, "Boat",
    PathTransition {
        duration: 5s 
        path: AnimationPath.createFromPath(path)
        orientation: OrientationType.ORTHOGONAL_TO_TANGENT
        repeatCount:Timeline.INDEFINITE autoReverse: true
    }
);

// Rotate the bubbles
animateNode(psobj, "Bubble",
    RotateTransition {
        duration: 3s 
        byAngle: 360 repeatCount:Timeline.INDEFINITE
        interpolator:Interpolator.LINEAR
    }
);

// Make the fish larger and smaller
animateNode(psobj, "Fish",
    ScaleTransition {
        duration: 1s
        toX: 0.8 toY: 0.8
        repeatCount:Timeline.INDEFINITE autoReverse: true
    }
);

// Move the balloons up and down while swinging back and forth
// by running two transitions at the same time
animateNode(psobj, "Balloon",
    ParallelTransition {
        content: [
            TranslateTransition {
                duration: 8s
                byY: 100 repeatCount:Timeline.INDEFINITE
                autoReverse: true},
            RotateTransition { duration: 5s byAngle: 30
                repeatCount:Timeline.INDEFINITE autoReverse: true},
        ]
    }
);

In the scene content, the only node that needs to be named is the one that represents the JavaFX graphic. The result is that the scene displays all the objects from the JavaFX graphic, even those with no ID, such as the background in this example, plus all of the functionality defined for individual nodes in the graphic.

Source Code: Apply Node Variables to Some Images
Stage {
    title: "Production Suite Graphic Example"
    scene: Scene {
        width: 527
        height: 602
        content: [
            psobj
        ]
     }
 }

The scene size was taken from the background graphic dimensions in the FXD description.

Where to Go Next