Jump into JavaFX, Part 2: JavaFX Script

Scripting in JavaFX: From language fundamentals to data binding

Before you can create rich internet applications in JavaFX, you need to get to know the JavaFX Script language. So, fire up your NetBeans IDE and take Jeff Friesen's scripted tour of JavaFX Script's language features. Learn how JavaFX Script handles basic constructs like variable declarations, fundamental types, and expressions; then jump into advanced features such as sequences, replace triggers, and data binding. Level: Beginner to Intermediate

The first part of this six-part series introducing JavaFX presented a Main.fx script that describes a "hello world" type of application. I didn't bother to describe the script's code, at the time, because it wouldn't make much sense without understanding the JavaFX Script language and associated APIs. In this article you'll be introduced to JavaFX Script, which should help you better understand Main.fx.

After a quick overview of JavaFX Script's background, we'll embark on a script-driven tour of its basic language features, including variable declarations, fundamental types, and expressions. Once you've got the basics under your sombrero, we'll advance to the next level of JavaFX Scripting, with a series of small programs that reveal how the language handles sequences, classes, and object literals. Finally, we'll discuss two advanced topics that could be challenging to Java beginners, and should be of interest to developers already using JavaFX Script; namely replace triggers and data binding.

JavaFX Preview SDK

The discussion in this article is based on the version of JavaFX Script found in JavaFX Preview SDK, which will differ somewhat from the version found in JavaFX SDK 1.0. What you learn here will serve as background for Jeff's first look at JavaFX SDK 1.0, in the final two articles of this series.

While not definitive, this guide to JavaFX Script does fill some holes in the current documentation, and should be code-driven enough to keep you engaged and learning from start to finish. Note that you need not know a thing about JavaFX Script to learn from this guide; you should, however, be familiar with the Java language and object-oriented programming concepts. Note, also, that what you learn in this article about JavaFX Script's syntax (primarily) will be enriched in Part 3, when we look at the JavaFX APIs.

From F3 to JavaFX Script

Just a little more than two years ago, Sun developer Chris Oliver introduced a project called F3 (Form Follows Function) via his blog. The project consisted of the F3 language and several APIs for simplifying GUI programming.

According to Oliver, F3 was "a declarative Java scripting language with static typing," which he said would provide IDE support and compile-time error reporting -- two features not found in JavaScript. The language also offered type-inference, declarative syntax, and automatic data-binding, with, as Oliver said "full support for 2D graphics and standard Swing components as well as declarative animation." Perhaps the biggest upside of using F3, according to its creator, was the ease with which it would allow developers to "import Java classes, create new Java objects, call their methods, and implement Java interfaces."

Hear this: Unwrapping JavaFX 1.0

In this JavaWorld podcast, Andrew Glover interviews Param Singh and JavaFX Architect John Burkey for a developer's perspective on what you'll be able to do with the newly released JavaFX 1.0.

Chris Oliver's brainchild, F3, is the basis of JavaFX Script, which Sun announced at the JavaOne conference in May 2007. We'll spend a lot of time in this article looking at how declarative syntax manifests in JavaFX Script. At the end of the article I'll show you some examples of the language's sophisticated data binding functionality. For now, though, just consider how these two features set JavaFX Script apart from many other languages:

  • Declarative syntax lets you specify what you want to achieve instead of how you want to achieve it. The result is a simpler syntax than the equivalent Java method call-based syntax used to create traditional Swing GUIs.
  • Data binding enables you to automatically update one or more GUI components whenever the state of another GUI component changes, without having to go to the trouble of registering various event listeners and providing code to perform these updates.

Another nice feature of F3 was declarative animation, which is also known as keyframe animation in JavaFX Script. Although declarative animation uses some syntactic sugar for ease of use, this feature is mostly API-based, so I won't discuss it until Part 3.

In the next section I'll introduce some of the fundamentals of JavaFX Script. As in the previous article in this series, you'll learn by doing, so you should start up your NetBeans IDE now. (See "Jump into JavaFX, Part 1" to get started with NetBeans 6.1 with JavaFX.)

JavaFX Script fundamentals

Start NetBeans and use the New Project wizard to introduce a new LanguageDemo project with languagedemo.Main as the main file. As we explore JavaFX Script, we'll insert a series of scripts into Main.fx, replacing the previous script with a new one.

The first thing you'll do is replace the skeletal Main.fx's "// place your code here" line with the following script -- as you enter this script, you'll probably encounter some of the IDE's editor features, including syntax highlighting, code completion, and small red octagon-shaped icons with exclamation marks that signify potential errors until the code is completely entered:

Listing 1. A first script

import java.lang.System;

var name1: String = "JavaFX";
var name2 = "JavaFX Script";
output ();

function output ()
{
    System.out.println (name1); // Output: JavaFX
    System.out.println ("name2 = {name2}") // Output: name2 = JavaFX Script
}

This script reveals a few interesting things about JavaFX Script. You'll notice right away that JavaFX Script supports the same single-line comment style as Java. It also supports the same multi-line and documentation comment styles. More importantly, you can include Java method calls in JavaFX Script code, but you'll want to import the appropriate Java packages to save keystrokes. For example, because JavaFX Script doesn't automatically import java.lang, you'll need to import this package, or prepend java.lang to each System.out.println() method call.

Now consider what else Listing 1 tells us about JavaFX Script.

Variable declaration

Variable declaration in JavaFX Script begins with the var keyword, continues with a valid name, is optionally followed by a type specification, and ends with an optional initializer for assigning an initial value to the variable. If a type isn't specified, the type is inferred from the initializer -- the type is unknown if there's no type and no initializer.

The name must follow Java's rules for what constitutes a valid identifier (it must not start with a digit, for example). Furthermore, the name must not be a reserved identifier (a literal such as null, true, or false; or a keyword used to name an operator, a statement-oriented expression, or something else).

Reserved identifiers

JavaFX Script reserves 67 (and probably additional) identifiers:

abstract, after, and, as, assert, at, attribute, before, bind, bound, break, catch, class, continue, delete, else, exclusive, extends, false, finally, first, for, from, function, if, import, in, indexof, init, insert, instanceof, into, inverse, last, lazy, let, new, not, null, on, or, override, package, postinit, private, protected, public, readonly, replace, return, reverse, sizeof, static, step, super, then, this, throw, trigger, true, try, tween, typeof, var, where, while, and with.

If you need to use a reserved identifier to name a variable or function (although you really shouldn't), or if you need to invoke an external Java method whose name matches a reserved identifier, you'll have to surround the reserved identifier with doubled angle brackets. Example: var <<var>> = 10; System.out.println (<<var>>).

Types, default values, and literals

Each variable has a type, whether or not the type is explicitly specified. This type can be a Java type, a JavaFX user-defined type, or one of the String, Number (double-precision float), Integer, and Boolean fundamental types -- you might argue that Void is also a fundamental type. These types are fundamental because they don't need to be imported.

The fact that the fundamental types are Java classes means that you can invoke their Java methods via variables or (except for Integer) values. For example, you can specify "abc".length (), 37.3.parseDouble ("23"), var i: Integer = i.parseInt ("23"); (but not 26.parseInt ("23")), and true.toString ().

If a variable isn't explicitly initialized, its type determines its default value: empty string for String, 0.0 for Number, 0 for Integer, false for Boolean, and null for reference types other than javafx.lang.Duration (which is 0.0 milliseconds). If there's no type, the variable's value defaults to null.

If the initializer is a literal, it must be compatible with the type (if present). Valid literals include sequences of characters between single quotes or double quotes (string literals), numeric values with decimal points (number literals), numeric values without decimal points (integer literals), true and false (Boolean literals), null, object literals, and time literals.

Functions

JavaFX Script's use of functions for specifying reusable blocks of code is also interesting. Although functions must have names (unless they're anonymous), return types don't need to be specified. If this type isn't present, and if no value is returned, the return type defaults to Void. To explictly identify this return type, specify it after the parameter list, as in function output (): Void {}.

A function's body is specified via a block. The last item of executable code within a block doesn't require a semicolon. In the previous script, the last item is a System.out.println() method call, which demonstrates yet another interesting feature: one or more expressions can be embedded within a string literal by surrounding each expression with brace characters ({}).

Finally, the script reveals that you can declare variables and functions outside of a class context, which is in sharp contrast to Java, where field variables and methods must be declared within classes. A variable declared in this manner is accessible to a function's code, although it can be hidden by declaring a same-named local variable within the function.

Running the script

Just one script has told us quite a bit about how JavaFX Script differs from the Java language, and also leverages it. After entering the script in Listing 1, compile and run the code by clicking the green triangle (Run Main Project) button on the toolbar (or press F6). As revealed in Figure 1, the output window displays the compilation results, and also all output sent to the standard output via System.out.println() method calls.

If compilation succeeds, the screen displays 'JavaFX' on one line, followed by 'name2 = JavaFX Script'.
Figure 1. Results of a successful compilation (click to enlarge)

Now that we've reviewed some language fundamentals, we can begin to look at expressions, which are the building blocks of JavaFX programs. We'll study some examples of simple expressions and review the operators for combining simple expressions into more complex ones. After that, I'll show you how JavaFX Script uses expressions to handle familiar Java constructs such as conditionals, loops, ranges, and exception handling, as well as expressions based on function pointers.

An expression language

According to Sun's JavaFX Script Programming Language Reference (currently in draft), JavaFX Script is an expression language. Apart from package and import statements, and variable declarations, everything else is an expression with zero or more inputs, and zero or one output. The script in Listing 2 demonstrates some simple expressions:

Listing 2. Simple expressions in JavaFX Script

var name = "JavaFX";
java.lang.System.out.println (name+" Script"); // Output: JavaFX Script
java.lang.System.out.println (name.equalsIgnoreCase ("JAVAFX")); // Output: true
java.lang.System.out.println (8 mod 3); // Output: 2
var circleArea = java.lang.Math.PI*10*10;
java.lang.System.out.println (circleArea); // Output: 314.1592653589793
var area = circleArea as Integer; // cast from Number type to Integer type
java.lang.System.out.println (area); // Output: 314
// The following expression demonstrates an alternative Number-to-Integer cast.
java.lang.System.out.println (circleArea.intValue ()); // Output: 314
java.lang.System.out.println (37.5.intValue ()); // Output: 37
// The following method call outputs: Hex equivalent of 1234: 04D2 
java.lang.System.out.println ("Hex equivalent of 1234: {%04X 1234}");
var millis = java.lang.System.currentTimeMillis ();
// The following method call outputs a date/time combination such as:
// Current date/time: Fri Sep 10 20:53:09 CDT 2008
java.lang.System.out.println ("Current date/time: {%tc millis}")

You might be curious about the {%04X 1234} expression in "Hex equivalent of 1234: {%04X 1234}", and the {%tc millis} expression in "Current date/time: {%tc millis}". These expressions reveal a language convenience for converting numbers and dates into formatted character sequences, via a java.util.Formatter formatting prefix followed by the item being formatted.

1 2 3 4 5 Page 1
Page 1 of 5