Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / containers / virtual-machine

Excerpt from JavaFX Developer's Guide

4.80/5 (4 votes)
21 Sep 2010CPOL23 min read 20.7K  
This chapter provides a high-level overview of JavaFX, from the core JavaFX platform to the tools that you can use to build and deploy JavaFX applications.

JavaFX-Developers-Guide.jpg

Kim Topley
Published by Addison-Wesley Professional
ISBN-10: 0-321-60165-3
ISBN-13: 78-0-321-60165-0

Built on top of Java, JavaFX is designed to simplify the process of creating applications that can be deployed across devices ranging from cell phones to desktops, with little or no additional work being required to move your code between these different device types. JavaFX applications are written using JavaFX Script, a new and easy-to-use language that is introduced in the second part of this chapter. The core of the platform is the JavaFX runtime library, which applications can use to build user interfaces, create animations, read data from RSS and Atom feeds, and to play video and audio files, among other things. After a brief discussion of the features of the runtime library, we look at the development tools that you can use to build JavaFX applications, and then we examine the options available for packing and deploying your application.

The JavaFX Platform

The JavaFX platform consists of a compiler, a set of runtime libraries, and some developer tools, including plug-ins for the NetBeans and Eclipse integrated development environments (IDEs) that enable you to develop JavaFX applications in a highly productive environment. One strength of JavaFX is that it runs on the Java platform, which means that an application written with JavaFX can make use of all the security and deployment features of Java and also has access to all the Java application programming interfaces (APIs) in addition to those provided by the JavaFX runtime itself. Figure 1-1 shows the overall architecture of the JavaFX platform.

kt01_01.jpg

Figure 1-1 JavaFX platform architecture

JavaFX applications are written in the JavaFX Script language, which is the subject of Part II of this book. JavaFX Script has a syntax that is close enough to that of Java to make it easy for Java developers to learn, yet different enough to make learning it an interesting and worthwhile experience. You'll find an overview of JavaFX Script later in this chapter.

JavaFX applications run under the control of the JavaFX runtime. At the time of this writing, there are three versions of the runtime: one for desktop environments, which runs on top of Java SE; another for mobile devices, which runs on Java ME; and a third version that runs on JavaTV. When you download JavaFX, all three versions are installed, and the correct version is automatically selected when you compile and test your applications in the NetBeans or Eclipse IDE.

The JavaFX runtime insulates the application from the details of the underlying Java platform, which means that it is possible, for the first time, to write a single application that can be deployed in multiple environments with little or no change. In other words, with proper use of the JavaFX APIs, you can write an application that will run on a desktop, in a browser (as an applet), on a cell phone (as a MIDlet), or on suitably equipped TVs. To do this, you do not need to understand the details of writing applets, MIDlets, or Xlets.

To make this possible, the JavaFX APIs are grouped into profiles. A profile is defined by the subset of the complete set of JavaFX APIs that it provides. At the time of this writing, there are two profiles:

  • The common profile, which contains those parts of the API that are available and work in the same way on all supported platforms. This includes the bulk of the user interface classes.
  • The desktop profile, which contains extensions that rely on the presence of the Java SE platform. One such feature is reflection, which is a part of Java SE but not of Java ME.

A JavaFX application that uses only features from the common profile can be deployed and executed on any device that supports JavaFX, but one that takes advantage of features of the desktop profile can be run only on platforms that support that specific profile. Some features can be used by any application but which do nothing on some platforms. An example of this is the Effects API, which is discussed in Chapter 20, "Effects and Blending." It is possible to use the javafx.runtime.Platform class, which we discuss in Chapter 12, "Platform APIs," to determine at runtime whether features that fall in this category are available to your application.

The API documentation that accompanies the JavaFX software development kit (SDK) indicates which packages and classes are provided with each profile. This book covers both the common and desktop profiles, and clearly indicates those features that are not part of the common profile.

The JavaFX Script Language

The JavaFX Script language was designed to make it easier for developers to write JavaFX applications and, specifically, graphical user interface (GUI) applications. As you'll see as you read through Part II of this book, JavaFX Script has several features geared to the needs of the GUI developer. You will also discover that JavaFX is a much more "relaxed" language than Java. For example, here is the canonical "Hello, World" example as it would be written in JavaFX Script:

// "Hello, World" in JavaFX
println("Hello, World")

As you can see, only a single line of executable code is required.1 Compare this to its Java equivalent:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World");
    }
}

In Java, you have to create a class, define a main() method with a specific signature, and then write the code that you want to execute. In JavaFX, you can skip the first two parts and just write the code. JavaFX does have classes, of course, but you will find that they don't feature nearly as prominently as they do in Java. In fact, this book hardly mentions user-defined classes until Chapter 11, "JavaFX Script Classes."

Variable Declarations

Variable declarations are more relaxed in JavaFX than they are in Java. Here's how you declare and initialize a string variable in JavaFX:

var hello = "Hello, World";

Variable declaration requires the keyword var (or def, as you'll see in Chapter 5, "Variables and Data Types"), but you don't have to specify the type of the variable—in this case, the compiler can deduce that its type must be String because of the way in which it is initialized. This feature of the language is called type inference and is discussed more fully in Chapter 5. In some circumstances, type inference does not work, but in the most common cases, this feature relieves you of the need to explicitly state the types of your variables.

Although a variable's type need not always be explicitly given, it is fixed once it has been determined. This means that, like Java, JavaFX is a statically typed language, by comparison with JavaScript, which supports dynamically typed variables and is consequently less type-safe. In JavaFX, the following code is not legal:

var hello = "Hello, World";
hello = 123;  // Error!

As a result of its declaration, the variable hello is of type String, even though this is not explicitly stated in the code. The type is permanently associated with the variable, so it is not legal to assign to it any non-String value, such as the numeric value 123 used in this example. In JavaScript and other dynamically typed languages, this reassignment of type would be legal.

Access to Java APIs

Although JavaFX has its own runtime libraries, JavaFX Script applications can also access the APIs provided by the underlying Java platform. For example, the following code uses the java.lang.System and java.util.Random classes to seed and print a random integer:

package javafxintro;
 
import java.lang.System;
import java.util.Random;
 
var random = new Random(System.currentTimeMillis());
println(random.nextInt(10));

The ability to access Java classes in this way makes it possible for JavaFX to leverage the existing capabilities of the underlying platform, such as networking or database access, where these features exist. However, relying on Java APIs might cause your application to become platform-dependent. For example, the following code is valid JavaFX, but it is not fully portable:

package javafxintro;
 
import java.lang.Math;
 
println(10 * Math.random());

The problem with this code is that the java.lang.Math class is only partially implemented on mobile devices—on Mobile Information Device Profile (MIDP)-based cell phones, of which many millions are currently in use, the random() method is not implemented. Consequently, this code will not compile if you attempt to build it for the JavaFX mobile profile. By contrast, the Random class that was used in the previous example is available in the MIDP profile of Java ME, so it is safe to use it in a JavaFX application that might run on a cell phone.2

Object Literals

A special syntax for object initialization in JavaFX, called an object literal, replaces the new keyword in Java. Here's an example of an object literal:

Text {
    x: 20
    y: 20
    font: Font { size: 24 }
    content: "Hello, World"
}

This code creates an instance of the javafx.scene.text.Text class and initializes its x, y, font, and content variables. The compiler ensures that the value to be assigned to each variable is compatible with its declared type. Object literals can be nested—in this example, a nested object literal is used to initialize the font variable with an instance of the javafx.scene.text.Font class in which the value of the size variable has been set to 24. Object literals are discussed in Chapter 5 "Variables and Data Types," and Chapter 6, "Expressions, Functions, and Object Literals."

Binding

Writing GUI applications often involves keeping different pieces of application state in sync with each other. For example, you might build a form containing an input field and an OK button and want the button to be enabled only when the input field is not empty. In Java, you do this by writing a listener that is called whenever the content of the input field is changed and either enables or disables the button depending on the field's content. In JavaFX, you can dispense with the listener and directly bind the state of the button to the input field's content, like this:

Button {
    text: "OK"
    disable: bind textBox.rawText.trim() == ""
}

Assuming that the textBox variable refers to an instance of the platform-independent text input control TextBox (discussed in Chapter 22, "Cross-Platform Controls"), the expression textBox.rawText gets the text that has been typed into the control, uses the trim() method to remove leading and trailing whitespace, and compares the result to the empty string.3 The result of this code is that the disable variable of the button will be set to true (thus disabling it, so that attempts to press it are ignored) if there is no text in the TextBox and false if there is. The bind keyword ensures that this linkage is maintained, so that as the content of the TextBox changes, the result will be recomputed and the value of the disable variable will be updated automatically. Binding is probably the single most useful feature of JavaFX, and you will see it used very frequently in the examples in this book.

Scripts and Compilation

JavaFX Script is compiled to class files by the JavaFX compiler and is then executed on the Java Virtual Machine (JVM). After a script has been compiled, it is indistinguishable from a compiled Java source file. The compiler is responsible for mapping each JavaFX Script source file to one or more class files. Most of the time, you do not need to be concerned with how this is achieved, because the tools that are shipped with the JavaFX SDK hide the details, as discussed in Chapter 3, "JavaFX Script Development," and Chapter 4, "A Simple JavaFX Application." One of the rare occasions on which you will see the mapping is when you need to analyze the stack trace of an uncaught exception. Fortunately, it is usually easy to map from the stack frames in the stack trace to your original JavaFX code.

JavaFX Script can also be compiled and executed on-the-fly by using the Java Scripting API, which is built in to Java SE 6 (and also available as a separate download for Java 5). This can prove useful if you need to download a script from a remote server and execute it on the user's platform. You can only do this if you have both the JavaFX compiler and the classes for the Java Scripting API available to the Java VM that is executing your application, which means that it is not possible to do this on platforms that provide only the common profile.

The JavaFX Runtime

The JavaFX runtime can be divided into two parts—the part of the runtime that is profile-independent and is used by both applications and the JavaFX compiler itself, and the part that is profile-dependent and on which the compiler has no dependencies. Some of the profile-independent runtime is directly used only by the compiler and the runtime libraries, but there are many public APIs that your JavaFX application can use, including the println() function that writes to the standard output stream, functions that let you read command-line arguments, applet parameters and system properties, and an API that lets you store information in a device-independent way. Many of these useful functions are covered in Chapter 12, "Platform APIs."

The APIs that are part of the common profile appear in all implementations of the runtime libraries. The code that implements these APIs in the three existing runtimes may not be the same, but the API itself is, and they are functionally equivalent. The runtime for JavaFX Desktop also contains implementations of the APIs that are unique to the desktop profile.

The runtime libraries are the subject of Parts III and IV of this book. Here, we briefly look at some of the most important features that they provide.

User Interface Classes

The majority of the runtime library consists of classes that are concerned with creating user interfaces. In JavaFX, a user interface is a collection of nodes. A node may represent a shape of some kind, such as a circle or a rectangle, some text, or something more complex such as a player for video or audio content. Nodes can be placed within a scene, which represents a complete user interface, or in a group, which is then placed in a scene or in another group. Operations are provided that enable you to move, rotate, scale, or shear individual nodes. Nodes in a group can be treated as a separate unit to which any of these operations can be applied. Applying a rotation to a group, for example, causes the whole group to be rotated.

Figure 1-2 shows a simple JavaFX application that consists of a number of nodes, running on a Windows PC. The background image is a node, as are each of the white circles that represent snowflakes. The text at the bottom of the application that counts the number of visible snowflakes is also a node.

kt01_02.jpg

Figure 1-2 A simple JavaFX application

This application uses APIs from the common profile only, so it can be run unchanged on any cell phone that is enabled for JavaFX. Figure 1-3 shows the same application running on a mobile device emulator. You'll see how this example is implemented in Chapter 4.

kt01_03.jpg

Figure 1-3 A JavaFX application running on a mobile device emulator

Video and Audio

JavaFX provides support for playback of video and audio streams on both desktop and mobile devices. Playing audio or video is just a matter of creating a specific type of node called a MediaView, placing it in a scene, and letting the JavaFX runtime do the rest for you.

Figure 1-4 shows an example of video playback on a PC running the JavaFX Desktop platform.

kt01_04.jpg

Figure 1-4 Video playback in JavaFX

As a general rule, you can play any type of audio or video for which the host platform has support. This means, for example, that JavaFX on the Windows platform can play anything that Windows Media Player can play. In addition, a couple of cross-platform formats can be played on any device that can run JavaFX. For further information, refer to the detailed discussion of the video and audio features of JavaFX in Chapter 19, "Video and Audio."

Animation

JavaFX has built-in support for animation, both in the language and in the runtime. Animation refers to the ability to vary the value of one or more variables over a specified period of time. If these variables represent the position of an object, the result will be that the object will appear to move. If, on the other hand, you were to vary the opacity of an object, that object would appear to fade in or fade out over time.

The following code uses both the compiler and the runtime support to create and play an animation that lasts for 10 seconds.

1      var t = Timeline {
2          keyFrames: [
3              at (0s) { node.translateX => 0 }
4              at (10s) { node.translateX => 200 }
5          ]
6      }
7      t.play();

The Timeline class, used on line 1, is part of the common profile in the JavaFX runtime. The code on line 3 says that at an elapsed time of 0 seconds, the translateX variable of the node referred to by the node variable (which is not shown in this code snippet) should be set to 0. The code on line 4 says that when 10 seconds has passed, the translateX variable of that same node should have the value 200. In between these two times, the variable will have intermediate values computed by the platform so that, for example, after 2 seconds the value might be (approximately) 40, after 4 seconds it might be 80, and so on.4 The translateX variable controls the horizontal position of a node, so the effect of this code will be that the node will appear to move horizontally across the screen at a uniform speed, covering 200 pixels in 10 seconds.

The syntax at (10s) and the symbol => are translated by the compiler into some more complex code that creates a KeyFrame object and initializes some of its variables. You will find all the details and many more examples of animation in Chapter 4, "A Simple JavaFX Application," and in Chapter 18, "Animation."

Network Access

Because JavaFX is intended to be used to write rich Internet applications, some support for retrieving data over the Internet would be expected. It is possible to use the networking support provided by the underlying Java platform, but there are two problems with this:

  • The networking APIs in Java SE and Java ME are very different from each other, which makes it impossible to write a platform-independent application that is also network-aware without also writing a platform-dependent glue layer to encapsulate the different networking APIs.
  • Accessing data over the Internet is a slow process that must not be performed in the thread that is used to manage the user interface. Unlike Java, JavaFX does not have language-level support for concurrency—there is no equivalent of the synchronized keyword. In fact, in JavaFX, application code is discouraged from managing threads.

To solve both of these problems, the JavaFX runtime provides classes that wrap common network operations and handle them in internally managed background threads. The intent is that an application should specify what needs to be done and then allow the runtime to take care of the details of handling it asynchronously. When the task is completed, application code is notified via a callback in the main thread. In this way, all the concurrency concerns can be managed by the JavaFX runtime in a manner appropriate to the host platform. For example, the runtime provides support for invoking an HTTP-based service, such as a RESTful Web Service, with asynchronous notification of the completion of the operation, together with progress reports as data is received. You'll find the details of these APIs in Chapter 27, "Using External Data Sources."

JavaFX Development Tools

The JavaFX SDK provides a set of tools that can be used to build and package a JavaFX application. It contains the following:

  • A command-line compiler that is based on the Java compiler and has the same command-line arguments. You can use this compiler to manually compile your application or as part of a batch script to build a whole project. A JavaFX-specific option allows you to specify whether to compile for the desktop, mobile, or TV version of JavaFX.
  • An Ant task that you can use to compile JavaFX source files using an Ant build file. The task simply runs the command-line compiler, passing it arguments obtained from the build file.
  • An application launcher that runs a JavaFX application. There is an option that determines whether the application should be launched in desktop, mobile, or TV mode.
  • A command-line utility called javafxpackager that builds a complete JavaFX application and packages it for delivery to either a desktop, mobile, or TV platform.
  • A command-line utility called javafxdoc that extracts documentation comments from a set of JavaFX source files and converts them to a set of HTML documents, in a similar way to the javadoc utility.

In addition to the command-line tools, there are plug-ins for both the NetBeans and Eclipse IDEs that enable you to compile, package, run, and debug your JavaFX application without leaving the comfort of your development environment. This book assumes that you will be using one of these plug-ins to run the example code, and you'll see how to use both of them when we create a simple but complete JavaFX application in Chapter 4.

It is possible to create graphical assets using commercial tools such as Adobe Photoshop and Adobe Illustrator that can then be imported into a JavaFX application. The JavaFX Production Suite, which is a separate download from the JavaFX SDK, provides plug-ins that export graphics from Photoshop and Illustrator in a format that is understood by the JavaFX runtime. You can also prepare artwork using an SVG (Scalable Vector Graphics) editor such as Inkscape. The JavaFX Production Suite provides a utility that enables you to view SVG files and convert them so that they can be read and used by your JavaFX application. These tools are discussed in Chapter 21, "Importing Graphics."

Deployment

A JavaFX application can currently be packaged and deployed for execution in four different ways:

  • As a desktop application delivered and installed using Java Web Start
  • As an applet delivered by a web browser and executed in the Java plug-in
  • As a TV application for a device that supports the JavaFX TV profile
  • As a mobile application delivered to a cell phone or other mobile device

The details of the packaging for each of these cases are handled by the javafxpackager utility, which we will discuss in Chapter 27, or by your IDE. However, some general points are worth noting here.

Java Platform Dependencies and Installation

Each version of the JavaFX platform has dependencies on the type of JRE (Java Runtime Environment) on which it is designed to run. For JavaFX Desktop, the minimum requirement is Java SE 5, although some features (for example, transparency) are not enabled unless Java SE 6 update 10 or higher is installed. For JavaFX Mobile, the minimum requirement is a device that supports Connected Limited Device Configuration (CLDC) 1.1, Mobile Information Device Profile (MIDP) 2.0, and the Mobile Services Architecture (MSA) specification, together with a suitable JavaFX runtime. For full details, refer to the Release Notes for the version of the JavaFX platform that you intend to use.

A long-standing issue with the use of Java as a desktop technology has been the need for the user to download and install an appropriate version of the Java platform. Even though most PCs and laptops now ship with a version of Java SE installed, it may be still necessary for the user to upgrade to a newer JRE in order to run a JavaFX application. Prior to Java SE 6 update 10, installing or upgrading the JRE meant waiting for a very large download to complete. By contrast, an application written using Adobe Flash, Flex, or Microsoft Silverlight requires a much smaller download and therefore would start much more quickly. Beginning with update 10, Java SE 6 includes a feature referred to as the Consumer JRE. The Consumer JRE splits the Java runtime into a small kernel that is initially downloaded, and various optional parts are fetched and installed only if they are required. The result of this is that Java applications, applets, and JavaFX applications that require a fresh or upgrade installation of the JRE will now start much more quickly than with earlier versions of the JRE.

The Java Plug-In

The original Java plug-in, which is responsible for hosting applets within the execution environment of a web browser, was the cause of many of the problems that resulted in Java applets being less popular than they should have been and contributed to the subsequent rise of alternative technologies like Flash, Flex, and Silverlight, including the following:

  • The initial phase of loading an applet is performed in the main thread of the browser, which causes the browser to freeze for a time whenever a web page containing a Java applet is visited, whether or not the user actually wants to use that applet.
  • Only one instance of the plug-in can execute within a browser instance, and that plug-in instance runs every applet within a single Java VM. This causes problems when it is necessary to run applets that require different versions of the JRE at the same time.
  • It is not possible for applets to change certain Java VM settings, such as the maximum heap size. This can make it impossible for an applet author to have sufficient control over the applet's execution environment to guarantee correct operation.

These problems were all fixed with the introduction of a new Java plug-in as part of the Java SE 6 update 10 release. Users who have this version of the JRE installed will have a much better experience with both JavaFX and Java applets than those using earlier versions, and further improvements are likely as a result of additional work being done to modularize the Java platform in Java SE 7.

Converting an Applet to an Installed Application

An interesting feature of the new Java plug-in that can be exploited by JavaFX applications is the ability to convert an applet to an installed application. The idea is to allow the user to see and experiment with your application by running it first as an applet within the web browser. In this mode, future use of the application requires the user to return to the hosting web page so that the applet is reloaded.

The new Java plug-in allows the user to immediately install the applet as an application by just dragging it from the web page and dropping it onto the desktop. After this has been done, the application becomes independent of the web browser and can be launched directly from the user's desktop. You'll learn how to use this neat little feature in Chapter 4.

  1. You might have noticed that there is no semicolon at the end of this line of code. A semicolon is needed only to separate two JavaFX statements, so in this case we can get away without one. You also don't need a semicolon after the last statement of a function or, more generally, after the final statement of a block. Of course, if your Java instincts were to cause you to add a semicolon here as a reflex action, that's okay, too—you won't get a warning or an error from the compiler. This is an example of the more relaxed syntax rules that make JavaFX easier to work with than Java.

  2. In this case, there is another alternative—the JavaFX runtime includes the class javafx.util.Math, which also includes a random() function. This function is part of the common profile and therefore is available on all JavaFX platforms.

  3. Notice that we use the == operator to compare the value of the rawText variable to the empty string. In Java, we have to use the equals() method to make this comparison, but JavaFX allows us to use == instead, because == is translated by the compiler to an invocation of equals(), as you'll see later in this book. This is another of the many ways in which JavaFX is more programmer-friendly than Java.

  4. The process of computing the intermediate values in an animation is called interpolation and is performed by an interpolator. The JavaFX runtime includes some standard interpolators, and you can also write your own. Refer to Chapter 18 for more information on this subject.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)