blob: 632018d0366b9e1611665b6a07c06ac67583e040 [file] [log] [blame]
<?php
/*******************************************************************************
* Copyright (c) 2015 Eclipse Foundation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eric Poirier (Eclipse Foundation) - Initial implementation
*******************************************************************************/
?>
<h1 class="article-title"><?php echo $pageTitle; ?></h1>
<p>
<a
href="http://www.oracle.com/technetwork/java/javafx/overview/index.html">JavaFX</a>
is Java's new rich client platform. With JavaFX it is easy to
create modern graphical user interfaces. It has built-in support
for visual effects and animations, supports touch-aware devices
and it includes an API for data-binding and event propagation.
JavaFX is the official successor to Java Swing but it will
result in much better looking apps.
</p>
<p>
<a href="http://www.xtend-lang.org">Xtend</a> is a statically
typed programming language developed at <a
href="http://eclipse.org/">Eclipse</a>. Based on Java, Xtend
removes the syntactic noise and adds the missing bits such as
type inference, lambda expressions, extension methods or
operator overloading. It is compiled to Java code and thus
integrates seamlessly with existing libraries and frameworks.
Xtend brings the fun back to Java programming without any
trade-off in terms of compatibility. Xtend's additional features
are a perfect match to the needs of a JavaFX programmer. It will
make your code shine the same way as a JavaFX application does.
In this article, I will demonstrate that with a couple of
examples.<br /> This article relates to Xtend version 2.4.
</p>
<h3>Event Listeners</h3>
<p>
Each JavaFX <a
href="http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html"><code
class="prettyprint lang-xtend">Node</code></a> has a couple
of convenience methods to react on UI events such as mouse
clicks, key strokes or multi-touch gestures. In Java a mouse
click can for example be handled with the following code:
</p>
<pre class="prettyprint lang-java">
// Java code
Rectangle node = new Rectangle();
node.setOnMouseClicked(new EventHandler&lt;MouseEvent&gt;() {
@Override
public void handle(MouseEvent event) {
System.out.println(event.getButton() + " button clicked");
}
});
</pre>
<p>
Let's see how we can improve this code by using Xtend. First of
all, Xtend's type inference allows to skip the type when it can
be inferred from the context. So the
<code class="prettyprint lang-java">Rectangle</code>
construction becomes
</p>
<pre class="prettyprint lang-xtend">
val node = new Rectangle
</pre>
<p>Note that semicolons can be skipped as well as empty
parentheses.</p>
<p>
Anonymous classes with a single method such as the
<code class="prettyprint lang-xtend">EventHandler</code>
instance is a very common Java idiom. Xtend improves on this
significantly by allowing to use <a
href="http://www.eclipse.org/xtend/documentation.html#lambdas">lambda
expressions</a> instead. The type is inferred from the actual
context. In the example the expected type is an
<code>EventHandler&lt;MouseEvent&gt;</code>
, so the lambda expression is automatically converted to this
type:
</p>
<pre class="prettyprint lang-xtend">
val node = new Rectangle
node.setOnMouseClicked([
MouseEvent event | println(event.getButton + "button clicked")
])
</pre>
<p>
The part
<code class="prettyprint lang-xtend">MouseEvent event |</code>
denotes the parameter list of the lambda. If the lambda has only
one parameter it can be skipped and it will be named
<code class="prettyprint lang-xtend">it</code>
. The parameter type is also inferred from the context, in this
case it must be
<code class="prettyprint lang-xtend">MouseEvent</code>
. Like
<code class="prettyprint lang-xtend">this</code>
you can omit
<code class="prettyprint lang-xtend">it</code>
as the receiver of feature call. Without the explicit parameter
the code looks like this:
</p>
<pre class="prettyprint lang-xtend">
val node = new Rectangle
node.setOnMouseClicked([
println(getButton() + "button clicked")
])
</pre>
<p>
Finally, Xtend has a <a
href="http://www.eclipse.org/xtend/documentation.html#featureCalls">shortcut
syntax for getters and setters</a>: Instead of
<code class="prettyprint lang-xtend">getButton()</code>
you can just write
<code class="prettyprint lang-xtend">button</code>
. Similarly,
<code class="prettyprint lang-xtend">setOnMouseClicked(arg)</code>
becomes
<code class="prettyprint lang-xtend">onMouseClicked = arg</code>
. Once again this is just syntactic sugar. The accessor methods
are still called. Our final result reads as:
</p>
<pre class="prettyprint lang-xtend">
val node = new Rectangle
node.onMouseClicked = [
println(button + "button clicked")
]
</pre>
<p>This snippet of Xtend code is completely equivalent to the Java
version above. It is a lot shorter, but it is still easier to
understand as all the syntactic noise has been cut out. Still
everything is type-safe and well defined.</p>
<h3>The With Operator vs Generated Builder Classes</h3>
<p>Sometimes a JavaFX object has quite a lot of parameters to be
customized. Instead of implementing a new constructor with a
huge number of parameters for each use case, the JavaFX
developers generated builder classes with fluent APIs, e.g.</p>
<pre class="prettyprint lang-java">
// Java code
Rectangle rectangle = RectangleBuilder.create()
.width(80)
.height(30)
.fill(Color.BLUE)
.stroke(Color.RED)
.strokeWidth(1.2)
.arcWidth(12)
.arcHeight(12)
.build();
</pre>
<p>
In Xtend the generated boilerplate is not needed at all because
there is the <em>with</em> operator
<code class="prettyprint lang-xtend">=&gt;</code>
that binds the preceding argument to the parameter of a lambda
expression and executes the latter:
</p>
<pre class="prettyprint lang-xtend">
val rectangle = new Rectangle =&gt; [
Rectangle r |
r.setWidth(80)
r.setHeight(30)
r.setFill(Color::BLUE)
r.setStroke(Color::RED)
r.setStrokeWidth(1.2)
r.setArcWidth(12)
r.setArcHeight(12)
]
</pre>
<p>
Using the implicit
<code class="prettyprint lang-xtend">it</code>
as closure parameter and the sugared setter call as explained
above our code becomes:
</p>
<pre class="prettyprint lang-xtend">
val rectangle = new Rectangle =&gt; [
width = 80
height = 30
fill = Color::BLUE
stroke = Color::RED
strokeWidth = 1.2
arcWidth = 12
arcHeight = 12
]
</pre>
<p>
Note that the Xtend code is shorter than the Java builder syntax
even though it does not require an extra builder class. In a
similar way, the <em>with</em> operator facilitates the creation
of object trees, e.g. subtrees of JavaFX's scene-graph.
</p>
<h3>Extension Methods For High-Level Property Binding</h3>
<p>
In JavaFX, the value of a property can be derived from other
properties by means of another fluent API for the calculation.
E.g. given two
<code class="prettyprint lang-xtend">DoubleProperties</code>
<code class="prettyprint lang-xtend">a</code>
and
<code class="prettyprint lang-xtend">b</code>
, you can bind a property
<code class="prettyprint lang-xtend">average</code>
which will be automatically updated when
<code class="prettyprint lang-xtend">a</code>
or
<code class="prettyprint lang-xtend">b</code>
change:
</p>
<pre class="prettyprint lang-java">
// Java code
average.bind(a.add(b).divide(2));
</pre>
<p>
When these calculations get more sophisticated and you do a lot
of them the code becomes very unreadable. This is the right
moment to think about <a
href="http://www.eclipse.org/xtend/documentation.html#operators">overloaded
operator extensions</a> for JavaFX's
<code class="prettyprint lang-xtend">DoubleExpressions</code>
. The code to overload an operator looks like this:
</p>
<pre class="prettyprint lang-xtend">
def static operator_plus(DoubleExpression a, ObservableNumberValue b) {
a.add(b)
}
</pre>
<p>
You would usually collect all such overloading methods in a
class
<code class="prettyprint lang-xtend">DoublePropertyExtensions</code>
and make them available using a <a
href="http://www.eclipse.org/xtend/documentation.html#extensionMethods">static
extension import</a> whenever you need them. The above Java
example becomes as simple as
</p>
<pre class="prettyprint lang-xtend">
import static extension my.company.DoublePropertyExtensions.*
//...
average &lt;&lt; a + b / 2
</pre>
<p>
Extension methods and operator overloading can also be used to
add the missing APIs for geometry calculation, e.g. to apply a <a
href="http://docs.oracle.com/javafx/2/api/javafx/scene/transform/Transform.html"><code
class="prettyprint lang-xtend">Transform</code></a> to a <a
href="http://docs.oracle.com/javafx/2/api/javafx/geometry/Point3D.html"><code
class="prettyprint lang-xtend">Point3D</code></a> or to
accumulate
<code class="prettyprint lang-xtend">Transforms</code>
. For detail please see the article on <a
href="http://koehnlein.blogspot.de/2013/01/accumulating-javafx-transforms-with.html">"Accumulating
JavaFX Transforms With Xtend"</a>.
</p>
<h3>Declaring Properties</h3>
<p>
JavaFX properties are usually wrapped in getters and setters
to comply with the <a
href="http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html">JavaBeans</a>
specification. For a lazily created
<code class="prettyprint lang-xtend">DoubleProperty</code>
<code class="prettyprint lang-xtend">radius</code>
the <a
href="http://blog.netopyr.com/2011/05/19/creating-javafx-properties/">recommended
code</a> looks like this:
</p>
<pre class="prettyprint lang-java">
//Java code
public class Balloon {
private DoubleProperty radius;
private double _radius = 20;
public double getRadius() {
return (radius != null)? radius.get() : _radius;
}
public void setRadius(double value) {
if (radius != null)
radius.set(value);
else
_radius = value;
}
public DoubleProperty radiusProperty() {
if (radius == null)
radius = DoubleProperty(this, "radius", _radius);
return radius;
}
// ...
}
</pre>
<p>
This is a lot of code for a simple property and a perfect use
case for a new language feature of Xtend: With <em>Active
Annotations</em> you can manipulate how Xtend is compiled to
Java. In our case, you could implement an <i>Active Annotation</i>
<code>@FXBean</code>
that describes the code pattern above. If an Xtend class is
annotated as
<code>@FXBean</code>
, this pattern is expanded for all its fields in the generated
Java code automatically by the compiler. So the Xtend version
becomes
</p>
<pre class="prettyprint lang-xtend">
@FXBean
class Balloon {
double radius = 20
//...
}
</pre>
<p>
The exemplary code for
<code>@FXBean</code>
can be found <a
href="https://github.com/svenefftinge/xtendfx/blob/master/xtendfx/src/xtendfx/properties/FXBean.xtend">here</a>.
Note that <i>Active Annotations</i> are loaded from the
classpath of the project at compile time, thus can reside in the
same workspace as the client code. They neither have to be
deployed to be used nor shipped with the application code. For
more infos on <i>Active Annotations</i> please refer to the
other article in the newsletter.
</p>
<p>
I hope I could convince you that JavaFX and Xtend make a perfect
couple. If you want to stay up-to-date with our work on Xtend, <a
href="https://twitter.com/xtendlang">join us on Twitter</a> or
ask your questions in our <a
href="https://groups.google.com/forum/?fromgroups#!forum/xtend-lang">Google
Group</a>.
</p>
<script
src="http://www.eclipse.org/xtend/google-code-prettify/prettify.js"
type="text/javascript"></script>
<script
src="http://www.eclipse.org/xtend/google-code-prettify/lang-xtend.js"
type="text/javascript"></script>
<script type="text/javascript">
prettyPrint();
</script>
<div class="bottomitem">
<h3>About the Authors</h3>
<div class="row">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-8">
<img class="author-picture"
src="/community/eclipse_newsletter/2013/march/images/jan_koehnlein1.jpg"
alt="Jan Koehnlein" />
</div>
<div class="col-sm-16">
<p class="author-name">
Jan Koehnlein <br />
<a href="http://www.itemis.com/">itemis</a>
</p>
<ul class="author-link">
<li><a href="http://koehnlein.blogspot.ca/">Blog</a></li>
<li><a href="https://twitter.com/jankoehnlein">Twitter</a></li>
<li><a href="https://plus.google.com/116635061773096754601">Google+</a></li>
<li><a href="<?php echo $original_url; ?>">Original Article</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>