Drawn together

Community post: JavaFX Loves Xtend

JanKhnlein
javafx-loves-xtend1

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
.

Author
Comments
comments powered by Disqus