In this article you will use JavaFX to develop a Rich Internet Application (RIA). JavaFX is not just a new technology for creating RIAs, but it is also a new programming language. It borrows heavily from the Java language and runs on the Java Virtual Machine. You do not have to be an expert Java programmer to create a JavaFX application, but familiarity with Java is helpful. You will need the JavaFX SDK; Version 1.0 of the JavaFX SDK was used to develop the code in this article. You will also need a Java Development Kit; JDK 1.6.0_07 was used to compile and run the code in this article. See the Download table for download links.
Explore JavaFX by developing a typical mashup application. The application will use a Web service from the popular photo sharing site Flickr. You will search Flickr for photos and display them in the JavaFX application. To start, you will model the data from the Flickr Web service using JavaFX.
Flickr offers RESTful Web services that can be called from any code, including JavaFX code. Calling the Flickr's services requires an API key that you can obtain for free from Flickr. It is possible to specify the format of the response from Flickr. The default is XML, and that is what will be used in this application. Sample output is shown in Listing 1.
Listing 1. Sample Flickr XML
<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
<photos page="1" pages="132147" perpage="6" total="792880">
<photo id="3196302982" owner="14994333@N08" secret="7c4e209fe9"
server="3536" farm="4" title="Pond" ispublic="1" isfriend="0" isfamily="0" />
<photo id="3196288734" owner="19764560@N00" secret="5142dd0a2d" server="3514"
farm="4" title="Pull In Case Of Fire" ispublic="1" isfriend="0" isfamily="0" />
<photo id="3195451611" owner="25304693@N00" secret="4ef1d2b63d" server="3528"
farm="4" title="Domein Nieuwenhoven" ispublic="1" isfriend="0" isfamily="0" />
<photo id="3196281786" owner="51865294@N00" secret="bed01bff0c" server="3403"
farm="4" title="Uitdam skyline" ispublic="1" isfriend="0" isfamily="0" />
<photo id="3196281752" owner="27734999@N03" secret="a81c2e53a5" server="3301"
farm="4" title="IMG_7642" ispublic="1" isfriend="0" isfamily="0" />
<photo id="3196281596" owner="51865294@N00" secret="c0f18f3aef" server="3510"
farm="4" title="Warm scene on a cold day" ispublic="1" isfriend="0" isfamily="0" />
</photos>
</rsp>
|
As you can see from Listing 1, each photo has several attributes that are important: id, secret, server, farm, and title. The first four of those are needed to create the URL of the image. Modeling this object using JavaFX is straightforward and is shown in Listing 2.
Listing 2. A Flickr image model in JavaFX
public class FlickrImage{
var id:String;
var secret:String;
var server:String;
var farm:String;
var title:String;
public function getUrl():String{
"http://farm{farm}.static.flickr.com/{server}/{id}_{secret}.jpg"
}
}
|
This simple class demonstrates several aspects of JavaFX's syntax. The keyword var is used to denote an instance variable in JavaFX. As you will see later, each of the vars in the class declaration becomes a named parameter when constructing an instance of the class. Notice that JavaFX is statically typed, with the type declared as a suffix to the variable's name.
The class also has a single method, getUrl. Methods are declared as functions in JavaFX, and they
are also statically typed. JavaFX has a return keyword that works just as
you would expect, but it is optional. It has been omitted in Listing 2, so
the last line of the function will be returned. In this case it is a
string expression. JavaFX will insert the instance variables into the
place holders in the string denoted using curly-braces. Note that this is
statically typed. So if you misspelled "secret" in the above example, or
tried to call a method on it that did not exist, you would get a
compile-time error.
Notice in Listing 2 that the vars have no access control modifiers. The default for JavaFX is script-private, so they will not be accessible from other classes. The lone method is declared as public, so it will be available to other classes. Now that you have a class to model images from Flickr, you just need a way to get some data to stuff into these classes. For that you will need to call the Flickr Web service.
JavaFX applications can make remote calls to Web
services. The javafx.io.http package contains
classes for asynchronously calling Web services. These classes in turn
rely on Java's networking stack. This is an important difference between
JavaFX and other RIA technologies that rely on the Web browser to make
remote calls. Given that, here is the sample application's model that
accesses Flickr's Web service for data (shown in Listing
3).
Listing 3. Model with data access code
var pics:FlickrImage[] = [];
public class Model {
public var tag:String;
public var onSuccess: function(FlickrImage[]):Void;
public function searchFlickr(){
delete pics;
var url=
"http://api.flickr.com/services/rest/?method=flickr.photos.
search&per_page=6&api_key={API_KEY}&tags={tag}";
var req = HttpRequest{
location : url
onInput: function(stream:InputStream){
parser.input = stream;
parser.parse();
onSuccess(images);
}
}
req.enqueue();
}
def API_KEY = "Put Your API Key Here";
var images:FlickrImage[] = bind pics;
}
|
This
code demonstrates several more key features of the JavaFX language. The
Model class has two public vars. One of
these is a simple string called tag. This is
the tag that will be used for the search query to Flickr. The other public
var, onSuccess, is a function. Functions are
first class objects in JavaFX. The declaration for onSuccess states that it is a function that takes an array of
FlickrImage objects as an input parameter and returns nothing (Void.) Any
function passed in to this parameter must satisfy this signature, or you
will get a compiler error.
These two public vars are both used in
the public function searchFlickr. Here you use
the HttpRequest class to make a call to the
Flickr Web service. Notice the syntax for creating an instance of HttpRequest. This is the declarative syntax of
JavaFX. In this case you are passing in two named parameters to the
constructor of HttpRequest. One is a string
called location, and the other is a function called onInput. Parameter name/value pairs are denoted by name :
value. So for the onInput parameter,
you
create an anonymous function. The static typing of JavaFX allows you to
know that onInput takes a function that takes a
java.io.InputStream as its sole input
parameter and has a Void return type. The onInput method above in Listing 3 passes the
InputStream to a parser object and then
invokes the onSuccess method that gets passed
into the Model instance. Finally, after
constructing the HttpRequest, you invoke its
enqueue method. This tells the JavaFX runtime to invoke the method as soon
as it has a free thread to do so. Do not use the main application
thread to make a remote call, as this would cause the application to
become unresponsive while you wait on the remote server.
Before
moving on to the parser code, you may have noticed a few more things in
the Model class and its searchFlickr method. It has an array (sequence) of FlickrImage objects called images. These are
bound to a script-level array called pics. Data binding is an important part
of JavaFX that allows one object to be changed, and those changes are then
propagated to other objects. In this case, any changes to pics will be
propagated to images. The very first line of the searchFlickr method uses the JavaFX keyword "delete" to clear
the data out of the pics sequence. Finally, notice how the API_KEY is declared as a def. This essentially
makes it a constant. Now we have covered everything in the Model class, so we are ready to move on to
parsing the data that comes back from Flickr.
Back in Listing
3 you saw a parser being referenced, and you saw a java.io.InputStream being passed to it. Mixing core classes
from Java with JavaFX is very common. In this case you are passing the
InputStream to a javafx.data.pull.PullParser. This is similar to a StAX parser
in Java. It allows you to receive a stream of events from the parser,
similar to SAX-style parsing, but with the ability to control the flow of
events, by only "pulling" the ones you want. JavaFX's PullParser works
equally well with both XML and JSON data—the two most common
formats for Web services. This makes JavaFX well suited for mashups like
the one being created in this article. Listing 4 shows the code for
parsing the XML from
Flickr.
Listing 4. Parsing XML in JavaFX
def ID = QName {
name : "id"
}
def SECRET = QName{
name : "secret"
}
def SERVER = QName{
name : "server"
}
def FARM = QName{
name : "farm"
}
def TITLE = QName{
name : "title"
}
def parser = PullParser{
documentType : PullParser.XML
onEvent : function(event:Event){
if (event.type == PullParser.START_ELEMENT){
if (event.qname.name.equals("photo")){
var image = FlickrImage{
id : event.getAttributeValue(ID)
secret : event.getAttributeValue(SECRET)
server : event.getAttributeValue(SERVER)
farm : event.getAttributeValue(FARM)
title : event.getAttributeValue(TITLE)
}
insert image into pics;
}
}
}
}
|
The first thing you will notice in the code in Listing 4 is that we define
several QName objects. These are qualified
names in XML terminology, and they represent the qualified names of
attributes in the XML coming back from Flickr. As you would expect,
JavaFX's QName class allows for a namespace and
a prefix, as well as the name. The Flickr XML (Listing 1) does not use
namespaces, so all you need is a simple name for the QNames in Listing 4.
The PullParser instance is created using JavaFX's declaration
syntax. This should start looking familiar! In Listing 4, you
simply indicate that you are parsing XML by setting the documentType
property. You then pass in an anonymous function (closure) to the onEvent property. You simply look for a START_ELEMENT event, and then if the element is
"photo", you pull out the data from its attributes and use this to create a
new FlickrImage instance. You need to add this
instance to the pics sequence. Notice how this is done using the JavaFX
reserved word insert. This will always add to
the end of the sequence. Finally you should note that all of the QNames and the PullParser are defined as defs (in other words, constants). You could
make them vars as well, but it is more correct to have them as defs. This
is similar to declaring them as final in Java.
Now we have looked at all of the data handling code. You have seen how to invoke a remote Web service and how to parse the XML that it returns. It is time to move on to the more glamorous user interface code that JavaFX is more well known for.
When JavaFX was first introduced at JavaOne in 2007, it was billed as a technology for creating rich user experiences. The UI aspects of JavaFX have always been stressed, so it should come as no surprise that JavaFX really shines in this area. Take a look at the user interface of our mashup. We will start by seeing how easy it is to extend some of the core classes in JavaFX.
The application needs
to show images from Flickr, so you need JavaFX's Image and ImageView classes. The
workflow is straightforward. Use a FlickrImage
object to calculate the URL of the image, create an Image instance using
that URL, and then create an ImageView object
using that Image. The ImageView object can then be added to a Scene (more on that later.) Let's encapsulate that logic with
a new class as shown in Listing
5.
Listing 5. A
FlickrView
public class FlickrView extends ImageView{
public var flickrImage:FlickrImage;
init {
this.image = Image {
url : flickrImage.getUrl()
}
}
}
|
As
you can see, the FlickrView class is a subclass
of ImageView. It adds a new var, flickrImage. The init
method is akin to a constructor in Java. It is called immediately after
all of the vars have been set by the caller. In this case it uses the
FlickrImage instance to create an Image
instance using the URL calculated by the FlickrImage. Subclassing is straightforward in JavaFX; it is
just like Java. Constructors are also easy using the init block. With the
FlickrView, it will be easy to display
images from Flickr, so you are ready to create the rest of the user
interface.
So far you have seen JavaFX's declarative style of syntax used in many places to construct new objects. This can be very convenient for developers. If you have done much JavaScript programming, then this style of programming is very familiar. It really comes into its own when you are creating the user interface. The main user interface of the application is shown in Listing 6.
Listing 6. User interface code
Stage {
title: "FlickrFX"
width: 500
height: 500
scene: Scene {
fill: LinearGradient {
startX: 0.0, startY: 0.0, endX: 0.0, endY: 1.0
proportional: true
stops: [ Stop { offset: 0.0 color: Color.ORANGE },
Stop { offset: 1.0 color: Color.BLUE } ]
}
content: VBox{
spacing : 50
content : [
HBox {
spacing : 20
content : bind topRow
},
HBox{
spacing : 10
content : [
Text {
font: Font {
size: 24
}
x: 10,
y: 30
content: "Tag"
},
input,
SwingButton {
text: "Search"
action: function() {
var model = Model {
tag : input.text
onSuccess : displayImages
}
model.searchFlickr();
}
}
]
},
HBox {
spacing : 20
content : bind bottomRow
}
]
}
}
}
|
This
code in Listing 6 may look a bit daunting at first, but it is actually
quite straightforward. Let's start at the top. The Stage is the main
display window of the application in this case. The code constructs a new
javafx.stage.Stage instance. It sets the
Stage instance's title var to FlickrFX and sets
its height and width vars to 500. If you stopped here, the application
would look like Figure 1.
Figure 1. Bare bones JavaFX application

This application isn't very interesting, but you get the idea. The next
thing that the code does is set the Stage instance's scene var. It sets
this to a new instance of the javafx.scene.Scene class. The first thing
that happens for the Scene is to create a background fill. In this case it
creates a gradient fill by setting the value of the Scene
instance's fill var to a new instance of javafx.scene.paint.LinearGradient. The gradient starts with
orange on top and finishes with blue on the bottom. LinearGradient's
startX, startY, endX, and endY determine where the gradient starts and
ends. This gradient will be vertical because startX and endX are the same,
but startY and endY goes from 0.0 to 1.0. Finally the LinearGradient's
stops var is set to an array of javafx.scene.paint.Stop objects. This is how you set where to
start the orange and blue. With the gradient code in place, the
application now looks like Figure 2.
Figure 2. Bare bones application with gradient

Well at least you have some color now! The only other thing you set on the
Scene instance is its content var. Set this to a javafx.scene.Node object. Node is an abstract class that is
the base class of all graphical objects in JavaFX. In this case you
construct a javafx.scene.layout.VBox instance.
The VBox is a container, and it will lay out its contents in a vertical
fashion from top to bottom. We set its spacing var to 50, so it will put
50 pixels between each object that it contains.
Objects are added to the VBox by putting them into a sequence of Nodes that are set to the VBox's content var. In this case you construct three javafx.scene.layout.HBox instances. As its name suggests, HBox is similar to VBox, but it lays out its contents horizontally, from left to right. Thus by stacking three HBox instances inside a VBox, you get a flexible grid.
The top and bottom HBox instances are bound to two other script variables, topRow and bottomRow. Again you have used JavaFX's powerful binding constructs. Whenever topRow or bottomRow are changed, the HBox instances will be changed, and thus those parts of the user interface will be refreshed. So what do you put in topRow and bottomRow? That code is shown in Listing 7.
Listing 7. Top and bottom row of the grid
def LOGO = Image {
url: "http://lh3.ggpht.com/_XmwdENwf53s/SW06N4aWEDI/AAAAAAAAAgo/
nXzkz7IBEnk/javafx.png"
}
var topRow = for (i in [1..3]) {
ImageView{
image: LOGO
fitWidth : 150
fitHeight : 150
preserveRatio: true
smooth: true
cache: true
}
}
var bottomRow = for (i in [1..3]) {
ImageView{
image: LOGO
fitWidth : 150
fitHeight : 150
preserveRatio: true
smooth: true
cache: true
}
}
|
Here
we have used another useful feature in JavaFX. The topRow and
bottomRow vars are constructed using a loop expression
(technically a list comprehension). This is a nice feature of JavaFX. The
equivalent Java code would not only be more verbose, but it would be less
obvious what it was doing. In this case, JavaFX's syntax makes it obvious
that you are creating a sequence of ImageView
instances, where each ImageView instance uses
the constant Image instance called
LOGO.
So that covers the top and bottom rows of the grid, but what
about the middle row? From Listing 6, you can see that it creates a label
(an instance of javafx.scene.text.Text) that
says "Tag" and a button. Actually the button is an instance of javafx.ext.swing.SwingButton. JavaFX leverages
many of the objects in Swing, but it makes them easier to use thanks to
its convenient syntax. The button says "Search", and its action var is set
to a closure. We will look at that in more depth in the next section.
Finally, the middle row also references another script variable called
input. This is created explicitly so that it can be referenced in other
parts of the code (namely in the button's action closure.) For
completeness, its code is shown in Listing
8.
Listing 8. The input control
def input = SwingTextField {
columns: 10
editable: true
}
|
Similar
to the button, this is also a Swing-based control. In this case it is an
instance of javafx.ext.swing.SwingTextField.
Note that it is once again a def, so that it cannot be mutated. Now that
you have all of the controls in place, let's take a look at what the
application looks like. It is shown in Figure 3.
Figure 3. Initial UI complete

Now all of the UI elements are in place. You are ready to hook up the view to the model created earlier. You will need some controller code to glue everything together and make this RIA interactive.
Gluing it together: JavaFX controls
Back in Listing 6, you saw that we had a button whose
action var was set to an inline function. Let's take a closer look at that
now. The function creates a Model instance
(Listing 3) passing in the value of the text var from the input object,
and a reference to another function called displayImages. The Model instance's
searchFlickr method is then invoked. From
Listing 3, you know that this displayImages function will be invoked once
the remote call to Flickr has completed and the results have been parsed
into FlickrImage objects. Take a look at the displayImages function in Listing
9.
Listing 9. Displaying images from Flickr
function displayImages(images:FlickrImage[]){
delete topRow;
delete bottomRow;
for (i in [1..3]){
insert FlickrView {
flickrImage : images[i-1]
fitWidth : 150
fitHeight : 150
preserveRatio : true
smooth : true
rotate : 60*(i-2)
} into topRow
}
for (i in [1..3]){
insert FlickrView {
flickrImage : images[i+2]
fitWidth : 150
fitHeight : 150
preserveRatio : true
smooth : true
rotate : -60*(i-2)
} into bottomRow
}
}
|
JavaFX
lets you write some fairly succinct code. The function deletes the
topRow and bottomRow, clearing out
whatever Nodes are in those sequences. It then uses JavaFX's for loop to iterate through the images object.
For each FlickrImage instance, a FlickrView instance is created and, using
JavaFX's insert statement, added to topRow or bottomRow. You
might also notice that each FlickrView instance has its rotate var
set as well. This is a var from Node (thus any graphical object can be
rotated). It takes a rotation in degrees to apply to the Node. This
gives you a fancy treatment for each image, as shown in Figure 4.
Figure 4. Showing images from Flickr

Keep in mind that the search results will change over time, even for "toast". If you look back at Listing 8, you will see that each image has its fitWidth and fitHeight vars set to 150, and the preserveRatio var is set to true. You can see the results in Figure 4. The JavaFX runtime dynamically resizes the images. The height and width are maxed out at 150 pixels, but the ratio of the height-to-width is preserved so the images are not distorted.
In this article, you have built a mashup using JavaFX. The mashup demonstrates how to invoke remote Web services and how to parse data coming from remote services. You have seen how to create a user interface using JavaFX and how to wire together controller logic to the user interface elements. These are some of the most common tasks in creating a mashup, and you have seen how JavaFX is designed to make these tasks easy. Along the way you have also seen examples of the important features of JavaFX's syntax: its type system, its support for closures, it sequence syntax, its powerful data binding, and its declarative syntax for constructing objects. Now you should be ready to create your own JavaFX-powered mashup.
| Description | Name | Size | Download method |
|---|---|---|---|
| Mashup source code | FlickrFX.zip | 3KB | HTTP |
Information about download methods
Learn
-
"Create
rich applications with JavaFX Script" (Cathy Kegley and Greg
Roberts, developerWorks, January 2008): This article provides a nice
introduction to JavaFX syntax.
-
"Create a
Java Applet to download information in remote Web services"
(Nicholas Chase, developerWorks, September 2008): JavaFX applications are
deployed as Java Applets. Brush up your Applet knowledge.
-
"Learning the JavaFX
Script Programming Language": Read another thorough overview of
JavaFX in this tutorial.
-
"Building GUI
Applications With JavaFX": Become an expert on the visual side of
JavaFX.
-
"JavaFX Media
Browser": Dive into JavaFX's rich media capabilities.
- Read Jim Weaver's JavaFX Blog
for expert tips and tricks on JavaFX.
- The Official JavaFX Blog: Get
the latest news or a glimpse into the future of JavaFX.
- JavaFX Community: Get involved
in the JavaFX Community.
- JavaFX Technology: Visit Sun's
JavaFX home to learn more about the technology.
- Planet JFX: Planet JFX
is an open source documentation wiki for the JavaFX scripting platform,
maintained by a community of early adopters, developers, and Java
enthusiasts.
-
"JavaOne
2007: Prodigal Sun returns to the client" (Elliotte Harold,
developerWorks, June 2007): Read about the promises and challenges of
JavaFX Script and other client-side initiatives introduced at JavaOne
2007.
-
""JavaFX Update: The
Elephant Is Through the Door!"" (James L. Weaver, AjaxWorld
Magazine, December 2007): Find out what the openjfx-compiler project is up
to.
-
"RESTful Web services and their Ajax-based clients" (Shailesh K.
Mishra, developerWorks, July 2007): Learn about combining RESTful Web
services, like the ones developed here, with Ajax applications.
-
"Introducing Project Zero: RESTful applications in an SOA" (Roland
Barcia and Steve Ims, developerWorks, January 2008): See how REST based
services fit in perfectly in a SOA system.
- "Invoke dynamic languages dynamically, Part 1: Introducing the Java
scripting API" (Tom McQueeney, developerWorks, September 2007): Learn about other alternative languages
running on the JVM.
-
"Build an Ajax-enabled application using the Google Web Toolkit and
Apache Geronimo" (Michael Galpin, developerWorks, May 2007): See
how Geronimo can be used with the Google Web Toolkit.
- Web development zone:
See the developerWorks Web development zone for a wide range of technical
articles, tips, tutorials, and standards.
- Flickr: Visit this online photo management application.
Get products and technologies
- JavaFX: This article
uses JavaFX 1.0.
- Java SDK:
This article uses Java SE 1.6_05.
- IBM trial
software: Innovate your
next open source development project with IBM trial software, available for download.
- Download IBM product
evaluation versions: Get your hands on application development
tools and middleware products from DB2, Lotus, Rational, Tivoli, and
WebSphere.
Discuss
- Participate in developerWorks
blogs.
Comments (Undergoing maintenance)






