Monday, February 15, 2010

JavaFx: Integrating with Java

JavaFx applications run on the JVM, which means that they must use class file formats that are compatible with those produced by the Java compiler. Which in turn means that JavaFx code should be able to call Java code and vice-versa. And, in fact, JavaFx to Java integration is easy:

import java.lang.Math;

var a = 12;
var b = 13;
var c = Math.min(a, b);
println(c);

var d = "this is a test";
var e = d.replaceAll("a test", "an example");
println(e);

Because of type inference, variables a and b are known to be integers, which are represented internally as int (not, as you may expect, as Integer — although that's no doubt an implementation detail and subject to change). This means that they can be passed directly to the Java method Math.min(). Similarly, variable d is known to be a java.lang.String, so you can invoke instance methods defined by that class.

Calling from Java into JavaFx is a little more difficult. Executing a script from a Java method is not practical: there are a number of methods that you must invoke, and the specific names and call order is undocumented. Script functions are compiled as public static methods, so you could theoretically import the script class and call these directory. However, any non-trivial script function would rely on script variables, which brings us back to the issue of setting up context.

JavaFx classes, however, are compiled as public nested (static inner) classes of their defining script. Which means you can instantiate a JavaFx class from within Java code. However, all of the instance variables will be set to default values — and the setter method names are, of course, implementation details and subject to change. Worse, NetBeans doesn't recognize that the compiled class exists, and flags your Java code as an error; you have compile manually (I didn't try Eclipse).

That leaves instantiating a JavaFx class from within JavaFx code, and passing it to a Java class for use. This is surprisingly easy, although convoluted. You first create a Java interface:

public interface CallbackIntf
{
    public void callback(String param);
}

A JavaFx class can then implement that interface:

class MyCallee
extends CallbackIntf
{
    override function callback(param : String)
    {
        println("callback invoked: {param}");
    }
}

Next, you instantiate your Java object from within the JavaFx script (in this example, Callback2), and then you can call a method on that object. Incidentally, note that we use new to instantiate the Java object, and can pass arguments into its constructor.

var caller = new Callback2("test");
var callee = new MyCallee;
caller.makeCallback(callee as CallbackIntf);

Convoluted, yes, but it offers promise: many framework objects (eg, Servlet) are specified as interfaces. If you're writing apps that could benefit from JavaFx language features (such as data binding), it's theoretically possible to do so and deploy into a Java framework. In practice, however, I don't think it will work. Threading is one reason, and that's the subject of my next post.

Friday, February 12, 2010

JavaFx: Building a GUI

JavaFx is targeted toward building graphical applications, and you'll find plenty of tutorials that walk you through such apps. Given this focus, I felt I should at least touch on GUI features.

Building the Containment Hierarchy

In a traditional Swing application, you start with a top-level window (a JFrame, or JApplet, or JDialog), and programmatically build out a “containment hierarchy” of components. For example, you'd build your main menu by instantiating a JMenuBar, then instantiating JMenu instances and adding them to it. For each JMenu instance, you'd then instantiate and add JMenuItem instances for the various menu choices. All Swing programs have a similar structure, which means there's a lot of boilerplate code. You could theoretically define the entire containment hierarchy as, say, an XML file, and eliminate the boilerplate. However, in practice you need to link together components and apply rules: for example, a menu item that should only be enabled when there's data for it to process.

A JavaFx application, however, is a step closer to declarative GUI design: the containment hierarchy (JavaFx calls it a “scene graph”) can be specified as a nested object initializer:

Stage {
    title: "Hello",
    width: 250,
    height: 80,
    scene: Scene {
        content: [
            Text {
                font : Font { size : 16 },
                x: 10,
                y: 30,
                content: "Hello, World"
            }
        ]
    }
}

The top level of the scene graph is the Stage. Unlike Swing, which uses different top-level classes for stand-alone applications versus applets, JavaFx uses Stage everywhere. As with other JavaFx GUI classes, Stage presents a much simpler interface than its Swing equivalents: a single scene for content, and a couple of callbacks for high-level events such as closing the window.

There are a couple of things that may not be obvious from this example. First: because the scene graph is constructed using an object initializer, you can extract parts of the initialization into variables — even bound variables:

var curText = "Hello, World";

Stage {
    // ...
                content : bind curText,
    // ...

The other important thing is this: creating a Stage creates and displays the window representing that stage. Swing, by comparison, separates construction and display. In the example above, we called the constructor without assigning the result to a variable. For simple applications, this is all you'll normally do. For more complex applications, you may construct multiple Stages, or hold onto them via variables so that you can modify them while the program is running.

Layout

Layout is one of the biggest pains of Swing programming. The Swing layout managers are all based on the idea that you need to position components mathematically, in order to deal with differing display resolutions and/or user actions (such as changing the size of a window). The result, more often than not, is an ugly UI. Or, alternatively, a custom layout manager that better suits the goals of a UI designer (I have several almost-complete articles on Swing layout, including a how-to on writing a layout manager; keep watching my main website feed to see when they appear).

JavaFx provides only a few, very basic layout managers. Most of the examples and tutorials use explicit layout: you provide the X and Y position of the object, and if needed, its width and height. There's also an option to extract layout information into an external CSS file. I haven't tried this, and am not certain why you'd do this; perhaps to deal with displays that have differing resolutions?

Interaction

JavaFx responds to user actions just like any other GUI environment: it invokes callbacks. If you've spent much time writing Swing ActionListeners, you'll probably like the fact that JavaFx supports first-class functions that you can specify as part of declarative initialization. If you've spent much time with JavaScript, you'll probably hate the fact that those functions are strongly typed, meaning that you have to specify parameters that you may never use.

JavaFx has a much simpler set of actions than Swing, and you can only attach a single function to a particular action. But be honest: how often did you actually use a list of listeners in Swing? Or intercepted Document events rather than just calling getText() on a field?

As I mentioned in my previous post, I think that bound fields will eliminate a lot of the code inside an action. As an example, consider a name/address form, along with a button that writes the form's contents to a database. In a traditional Swing app, that button's action handler would have to explicitly retrieve the contents of every field on the form, use those values to populate an object, then pass that object on to the database. With JavaFx, you could bind the fields of the object to the fields on the form, and the action would simply submit the already-populated object (although if the object's fields remained bound, the user could continue to update them — perhaps JavaFx could benefit from a value-based copy constructor).

CustomNode

A scene graph is a tree of javafx.scene.Node objects, with the Scene at the top, and various combinations of grouping and rendered components under it. The CustomNode class allows you to create new combinations of components that occupy a place in that hierarchy. For example, a field object that consists of both a label and a text field, with consistent sizing.

Note that I said “create”: one of the anti-patterns of Swing programming is to subclass JPanel just to add components to it (that anti-pattern is the topic of another forthcoming article on my website). When you subclass CustomNode, you are actually creating a controller class. You must override the abstract function create() to build out the node's containment hierarchy.

Graphics and Animation

JavaFx provides a simplified interface to the Java2D library. In Swing, if you want to access the drawing primitives, you must subclass a Swing component (usually JPanel) and override its paintComponent() method. JavaFx gives you components that already do this; you simply create a node in the scene graph. You specify the object's position, size, stroke, fill, and transforms in its initializer.

Graphical objects and data binding come together in JavaFx animation. Here's a simple countdown timer, with explanation to follow:

var counter = 10;

Stage {
    title: "Countdown",
    width: 100,
    height: 40,
    scene: Scene {
        content: [
            Text {
                font : Font { size : 18 },
                textOrigin: TextOrigin.TOP,
                x: 60, y : 10,
                content: bind counter.toString();
            }
        ]
    }
}

Timeline {
    keyFrames: [
        at (10s) {
            counter => 0 tween Interpolator.LINEAR;
        }
    ]
}.play();

The scene graph is simple: a single text field. Its content is bound to the variable counter; every time that variable gets updated, the text field will be updated as well. Where this program gets interesting is the Timeline object, particularly its keyFrames property.

A Timeline is like a javax.swing.Timer on steroids. You tell it the desired value for one or more variables at fixed points in time, along with a way to interpolate between the starting value and the desired value, and the Timeline will make that happen. Here I specify that, at 10 seconds after the timeline starts, the value of counter should be zero, and that it should change linearly. I start with the value 10, the Timeline constantly invokes the interpolator to compute the “current” value, and then sets the specified variable (which is in turn bound by the text field).

Animation is considered such a big deal that the at operator is a part of the language. As far as I can tell, all that it does is instantiate a KeyFrame object. Unfortunately, the Animation chapter of the Language Reference is currently empty. As a result, figuring out animations is a matter of looking at examples and experimenting.

Profiles

One of the problems with J2ME development is that you don't have the full Java environment: there's no floating point, and a very limited subset of the API. JavaFx attempts to rectify this, but even so, its API breaks out into two categories: common and desktop. The desktop profile provides OpenGL graphical effects (the entire javafx.scene.effect package), as well as the ability to use Swing components.

This Isn't Your Father's GUI

Looking through the API docs, I was struck by what's missing: there aren't any menus. Nor tables. This is intentional: as I learned from a HanselMinutes podcast, the JavaFx team is not trying to build the next toolkit for corporate applications. Indeed, looking at what they've done, I hear “mobile app”: a simplified UI, with flashy controls, designed to fit in a small space. Which is not a bad thing.

Wednesday, February 10, 2010

JavaFx: Bound Variables

One of the things that I find most interesting about the JavaFx language is binding: you bind a variable to an expression, and the value of the variable changes whenever the expression changes:

var a = 12;
var b = bind 2 * a;

println(b);
a = 17;
println(b);

In this example, the value of b starts out as 24 — 12 * 2. However, when a is updated, the value of b changes: it's now 34.

Binding is implemented using an Observer pattern, rather than lazy evaluation: b is recalculated at the time a is changed (the compiler attaches a “listener list” to all variables involved in a bound expression). Functional purists may be muttering under their breath at this point, but this approach does allow a couple of interesting features.

First, it means that the runtime does not need to completely re-evaluate a bound expression: the compiler memoizes sub-expressions, and only recomputes those that depend on the changed value. This can be useful if the bound expression includes a long-running function:

function longRunningFunction() {
    println("longRunningFunction() invoked");
    2;
}

var a = 12;
var b = bind a * longRunningFunction();
println(b);

a = 13;
println(b);

Second, it means that you can create bidirectional binds, in which changing the value of either variable will change the other. This can be useful if you have two linked input fields:

var x = "foo";
var y = bind x with inverse;

println("before change, x = {x}, y = {y}");
y = "bar";
println("after change, x = {x}, y = {y}");

Binding isn't limited to discrete variables. You can pass a bound expression into a class initializer, and that particular instance of the class will be updated as the expression changes:

class MyClass {
    var x : Integer;
}

var a = 12;
var b = MyClass { x : bind a };
var c = MyClass { x : a };

println("before change: b={b.x}, c={c.x}");
a = 13;
println("after change: b={b.x}, c={c.x}");

When the class is a GUI object, binding becomes a low-effort way to implement MVC: simply bind the relevant fields of the GUI object (view) to the relevant fields of the model object. Having written more than my share of event listeners and active models, this approach seems very civilized.

Binding does, however come with a performance hit: I wouldn't want to bind to a variable that will be updated frequently. And I can imagine a program filled with “spaghetti binds” that are impossible to untangle. It's like any new feature: “with great power comes great responsibility.” I'm sure we'll go through a phase of gratuitous binding, but once programmers get that out of their system we'll have programs that are easier to maintain.