Community post: JavaFX Loves Xtend

Jan Köhnlein on how using Xtend with JavaFX can result in astonishingly short yet powerful code.
In a new feature for 2013, we’re each week going to
highlight a blog post from a member of the community (with their
explicit permission, of course). This week’s post comes from Jan
Köhnlein, who blogs at koehnlein.blogspot.co.uk and
can be followed on Twitter and Google+.
Inspired by a talk by
Gerrit Grunwald and
the work of Tom
Schindl I started to dig a bit deeper into JavaFX. Being one of
the committers of the Xtend
language, it was a matter of honour to use Xtend in my
experiments.
The result: JavaFX and Xtend seem to be made for each other.
If you know me a bit, you won’t be surprised that I tried
implementing a simple graph editor first. I will blog on that
particular application in a separate post. Even though JavaFX is
not primarily a graphical editing framework, it offers a lot of the
required features, e.g.
- State of the art rendering and CSS styling
- A life scene-graph with affine transformations in all nodes
- An easy way to do data-binding and event propagation
- Easy to use APIs for effects and animations
- Built-in support for tablets and touch-aware devices
The developers of JavaFX did a pretty good job in creating a
clear Java API, but sometimes Java’s rigid syntax was a bit in
their way. This is where Xtend comes into play. The resulting code
is astonishingly short and easy to read.
Lambda expressions for event listeners
Each JavaFX Node
has a couple of convenience methods to react on on UI events, such
as mouse clicks, key strokes or multi-touch gestures. A mouse click
can for example be handled as
Node node = new Rectangle(); node.setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { System.out.println(event.getButton() + " button clicked"); } });
Xtend’s lambda expressions (aka closures) are automatically
coerced
to interfaces with a single method. Using the implicit
parameter it and the shortcut
syntax for property access the above becomes :
val node = new Rectangle node.onMouseClicked = [ println(button + " button clicked") ]
The with operator => obsoletes builders
JavaFX has a couple of objects that need quite a few parameters to
be customized. Instead of implementing a new constructor with a
huge number of parameters for each use case, the JavaFX developers
generated fluent builder APIs, e.g.
Rectangle rectangle = RectangleBuilder.create() .width(80) .height(30) .fill(Color.BLUE) .stroke(Color.RED) .strokeWidth(1.2) .arcWidth(12) .arcHeight(12) .build();
In Xtend, we have the with operator ‘=>’ that binds the
preceding argument to the parameter of a lambda expression and
executes the latter. So we can achieve the same as above with an
even shorter syntax and without the need for an accompanying
builder class:
val rectangle = new Rectangle => [ width = 80 height = 30 fill = Color::BLUE stroke = Color::RED strokeWidth = 1.2 arcWidth = 12 arcHeight = 12 ]
The with operator also facilitates the creation of object trees,
e.g. subtrees of JavaFX’s scenegraph.
Extension methods for high-level property
binding
In JavaFX, properties can be derived from other properties by means
of another fluent API for the calculation. The result is the best
you can achieve with pure Java, e.g. given two DoubleProperties a
and b, you can bind a mean value property which will be
automatically updated when a or b change:
mean.bind(a.add(b).divide(2));
If these calculations get more difficult and you do a lot of them
it will get quite unreadable. This is the right moment to think
about overloaded
operator extensions for DoubleProperties. With these, the last
line can become as simple as
mean << a + b / 2
Extension methods and operator overloading can also be used to add
the missing APIs for geometry calculation, e.g. to apply a
Transform to a Point3D
or to accumulate Transforms.
For more on Eclipse Xtend, check out our
interview with contributors Sven Efftinge and Sebastian
Zarnekow.