Desktop Java

JavaFX 2.0 and Scala, Like Milk and Cookies

JavaFX 2.0 and Scala are both great technologies individually, but work even better when used together. JavaFX 2.0 is a powerful rich client technology with advanced graphics, animation, and media capabilities. Scala is a simple, yet powerful language with advanced language features for writing domain-specific languages (DSLs). Add a little Scala UI DSL to your JavaFX 2.0 project and you will be in cookie and cream heaven!

JavaFX Colored Circles

I will go into more detail on why Scala in a bit, but I believe this is all best illustrated with a code example. One of the basic examples of JavaFX 2.0 functionality that comes with the SDK is a sample application called ColorfulCircles. The full source code can be found here:

– Java Colored Circles Code

With the help of Sven Reimers, we ported this to Scala on top of the ScalaFX library. The working application source can be found here:

– ScalaFX Colored Circles Code

Update: Dean Iverson has a great example of the same code in GroovyFX
Feel free to peruse the source code at your leisure, and take note of the following:

1. ScalaFX is More Concise

The ScalaFX version is shorter both in number of lines and more importantly number of characters.
Code Count (excluding licenses and imports):

  • Lines:
    • Java: 48
    • ScalaFX: 42
  • Characters:
    • Java: 1602
    • ScalaFX: 866

This is due to custom tailored DSL language that is fully expressive with less redundancy. In the Java version of the code you will notice a lot more boilerplate and syntactic repetition that is required by the language.

2. ScalaFX Code Looks Like the Output

While the output of the Colored Circles example is quite simple, it actually hides quite a bit of complexity in the way it is structured. Here is the output run from JavaFX 2.0 Build 45 using ScalaFX:

What you are actually seeing is a SceneGraph composed of the following layers:

  • A Scene with a black background that contains…
    • A Group that contains
      • 30 semi-transparent Circles covered by…
    • A rainbow-colored Rectangle overlay

When reading the ScalaFX code you get this nesting through the object-literal style declaration of the Nodes in the Scene as excerpted here:

// ScalaFX Scene Excerpt:
scene = new Scene {
  content = Seq(
    new Group {
      circles = for (i <- 0 until 30) yield new Circle { ... }
    }
    new Rectangle { ... }
  )
}

However, the Java version does not give you the same hierarchical representation, and instead uses an imperative series of calls to constructors, getters, and collection methods.

3. Tailored Animation Syntax

Animations are very commonly used in creating good UIs, which is why JavaFX Script had a built-in construct to simplify the creation of animations. ScalaFX has a similar syntax that allows you to quickly and easily create animations, which is used in the ColorfulCircles example:

Seq(
  at(0 s) {circle.centerX -> random * 800},
  at(0 s) {circle.centerY -> random * 600},
  at(40 s) {circle.centerX -> random * 800},
  at(40 s) {circle.centerY -> random * 600}
)

This makes it trivially easy to create complex animations.

4. And the ScalaFX Version Has a Hidden Bonus Feature…

Unlike the JavaFX version, the contents are bound to the width and height of the stage. Binding in ScalaFX is as simple as replacing the assignment operator (=) with the bind operator (<==) as shown here:

// ScalaFX Property Setting:
width <== scene.width
height <== scene.height

While this is a simple operator change in ScalaFX, it requires complex enough code that they decided to omit it from the JavaFX sample. A loose translation to Java would be the following:

// Java Fixed Property Binding
colors.widthProperty().bind(scene.widthProperty())
colors.heightProperty().bind(scene.heightProperty())

Although, the precise equivalent code in Java syntax would actually be the following:

// Java Dynamic Property Binding
colors.widthProperty().bind(Bindings.selectDouble(primaryStage.sceneProperty(), "width"))
colors.heightProperty().bind(Bindings.selectDouble(primaryStage.sceneProperty(), "height"))

Either of these versions is quite a bit more complex and unwieldy than the ScalaFX equivalent, and this is for a very simple binding!

About ScalaFX

ScalaFX is a UI DSL written within the Scala Language that sits on top of JavaFX 2.0 (not to be confused with Ingo Maier’s great work on Functional Reactive Programming for Swing). This means that every ScalaFX application is also a valid Scala application. By extension it supports full interoperability with Java and can run anywhere the Java Virtual Machine (JVM) and JavaFX 2.0 are supported.
Some of the features of ScalaFX include:

A Programmer-Friendly Object-Literal-Like Syntax

ScalaFX uses a simple, hierarchical pattern for creating new objects and building up the scene graph. Here is a simple example that creates a new stage with a rectangle that changes color based on mouse events:

stage = new Stage {
  title.value = "Hello Stage"
  width = 600
  height = 450
  scene = new Scene {
    fill = Color.LIGHTGREEN
    content = new Rectangle {
      x = 25
      y = 40
      width = 100
      height = 100
      fill <== when (hover) then Color.GREEN otherwise Color.RED
    }
  }
  visible = true
}

Unlike the builders you find in the core JavaFX APIs, the ScalaFX object declaration syntax uses the normal object API. This means that you can use the same operators and convenient syntax to create and modify your scene graph. Also, anything that is permissible in a Scala block (such as variable declarations, method calls, binding, etc.) can also be done inline while constructing objects. For JavaFX builders you need to declare binding after you finish creating your objects, which leads to disassociated and hard to maintain code.

Natural Language Bind Expressions

One of the greatest advantages of using the Scala language as a DSL is the rich support for operators as methods. This is similar to the C++ concept of operator overloading, but much more uniform and clean in its application.
The ScalaFX bind library exposes normal operators such as &&, ||, +, -, *, / on top of all bindable objects. Also, Scala supports operator precedence, so it looks and feels like you are writing normal expressions even though you are creating bound objects under the covers. As a result, you have the full functionality available from the JavaFX 2.0 binding libraries with code that looks akin to mathematical expressions and operators.
Here are some examples of what you can do with the ScalaFX bind API:
Infix Addition/Subtraction/Multiplication/Division/etc.

height <== rect1.height + rect2.height

Aggregate Operators

width <== max(rect1.width, rect2.width, rect3.width)

Conditional Expressions

color <== when (hover) then Color.GREEN otherwise Color.RED

Complex Boolean Expressions and String Concatenation

text <== when (rect.hover || circle.hover && !disabled) then textField.text + " is enabled" otherwise "disabled"

Free-form Invalidation and Change Handlers

rect.hover onInvalidate {
  needsRepaint = true
}

Fully Type-Safe APIs

This may seem like an insignificant point… Type safety is something that Java developers have always had (and often take for granted), and developers in other scripting languages live without (and unknowingly suffer with runtime errors as a result). However, it is a critical feature if you are developing applications that cannot have unexpected runtime errors and bugs after deployment.
A good compiler will be able to pick up many common coding mistakes through comparison of expected and actual types, and a great compiler (like Scala) will automatically infer types for you so you don’t have to tediouisly repeat them throughout your code.
ScalaFX gets the best of both worlds with a scripting-like DSL syntax where you can rarely have to explicitly type objects, with the strong type-safety of the Scala compiler that will infer and check the types of every expression and API call. This means less time spent debugging weird code bugs and misspellings, and higher quality code right out of the gate!

Seamless JavaFX/ScalaFX Interoperability

It is often the case that you do not have complete freedom about the predominant language of the codebase, or of the libraries you are including functionality from. Even in a mixed environment codebase where you have Java, Scala, and possibly other JVM languages, ScalaFX will seamlessly convert and interoperate.

ScalaFX gets this functionality through the implicit operator capabilities of Scala. Anywhere your program expects a JavaFX typed object, it will automatically insert the code to convert from ScalaFX wrapped objects to JavaFX native classes. Any time you use a ScalaFX specific feature, the compiler automatically creates a ScalaFX wrapper object that allows you to call advanced methods and access the full functionality. This all happens behind the scenes, letting you focus on writing clean code, and not fussing about integration and interoperability.

With all this interoperability magic happening behind the scenes, there is some additional overhead on your application. We have taken pains to minimize this using features like @specialize in the Scala language, which allows us to avoid boxing and unboxing costs on primitives. However, without real benchmarks it is hard to tell just how good of a job we have done. Hopefully more on this in a future post.

Finding out More About ScalaFX

The ScalaFX project site is hosted by Google Code including a couple mailing lists that you should join if you are interested:

At the time of writing we do not have a bundled release, but are interested in early adopter feedback. If you would like to give it a try, please download the source and give it a quick spin!
I will have more details about ScalaFX at my upcoming JavaOne session with Dean Iverson entitled “JavaFX 2.0 With Alternative Languages“. Come to hear more about Scala, Groovy, and other JVM languages you can use to write simpler, cleaner code.

Reference: JavaFX 2.0 and Scala, Like Milk and Cookies from our JCG partner Stephen Chin at the Steve On Java blog.

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button