Java Magazine Logo
Originally published in the July/August 2014 issue of Java Magazine. Subscribe today.

JavaFX with Alternative Languages

by Josh Juneau

Published July 2014

Alternative languages and custom APIs enable rapid JavaFX application development.

In this day and age, the more tools you have in your toolbox, the better. That is, it makes sense to know more than one way to implement a solution, because in some cases one implementation might have advantages over others. Although the JavaFX 8 API is very nice, there are advantages to knowing more than one way to develop a JavaFX application.

This article demonstrates how to develop JavaFX applications using alternative languages, so that you can add some additional tools to your toolbox. In the first section of this article, we’ll take a look at a JavaFX drawing application, and we will compare its implementation across a couple of different languages. In the second section, we will take a look at GroovyFX, a JavaFX API for the Groovy language, which is focused on rapid JavaFX application development.

Note: The source code for this article can be found on GitHub.

Bare-Bones JavaFX Development with Alternative Languages

In this section, we will not use any special APIs, but rather, we will implement a simple JavaFX application using only the standard features of a couple of different languages.

The application in this section is written using JavaFX 8 without FXML, and it is a drawing application. It allows the user to select from a handful of different colors, change the size of the pen, and reset the canvas to do it all over again. The application contains two ChoiceBox nodes for choosing the color and size of the pen, a Canvas to draw upon, and a Button to reset the canvas. Figure 1 shows what the application looks like when it is executed (and a great artist has spent some time sketching).

RichClient-f1

Figure 1

Take a look at Listing 1, which contains the complete code for the application, written using the JavaFX 8 API. As with all JavaFX applications, it is launched via the execution of a main() method, and the start() method contains the primary stage construction and much of the application implementation.

Note: The following listing has been excerpted for space, as noted by the ... symbol. The full code listing is available by downloading the code listings for this issue.

public class JavaFXDraw extends Application {

    public static void main(String[] args) {
        Application.launch(JavaFXDraw.class, args);
    }
    @Override
    public void start(Stage primaryStage) {

        StackPane root = new StackPane();
        Screen screen = Screen.getPrimary();
        Rectangle2D rect = screen.getVisualBounds();
        Canvas canvas = new Canvas(rect.getWidth()/2 + 50,
                rect.getHeight()/2 + 300 );
        final GraphicsContext graphicsContext = 
                canvas.getGraphicsContext2D();

        final Button resetButton = new Button("Reset");
        resetButton.setOnAction(actionEvent-> {
            graphicsContext.clearRect(1, 1, 
            graphicsContext.getCanvas().getWidth()-2, 
            graphicsContext.getCanvas().getHeight()-2);
        });
        resetButton.setTranslateX(10);

        // Set up the pen color chooser
        ChoiceBox colorChooser = new ChoiceBox(
            FXCollections.observableArrayList(
        "Black", "Blue", "Red", "Green", "Brown", "Orange"
        ));
…

Listing 1

To note a few pieces of code in particular, let’s first take a look at the Reset button event handler, because it is implemented using a lambda expression. When the user clicks the Reset button, the canvas is cleared.

Next, let’s look at one of the canvas action listeners, which in JavaFX 8 can also be written as a lambda expression. When the user presses the mouse button while on the canvas, a stroke marks the canvas until the mouse button is released:

canvas.addEventHandler(
    MouseEvent.MOUSE_PRESSED,
      (MouseEvent event) -> {
  graphicsContext.beginPath();
  graphicsContext.moveTo(
          event.getX(),
          event.getY());
    graphicsContext.stroke();
});


The rest of the code is fairly straightforward. The two ChoiceBox controls are constructed containing observable array lists of values. The Button and ChoiceBox controls are grouped together within an HBox, which is then added to the top of a BorderPane, and the Canvas is added to the center of the BorderPane. Finally, the BorderPane is added to a StackPane to create the stage. Before the stage is fully constructed and made visible, the Canvas is initialized by calling a separate initDraw() method. Now let’s take a look at how this same application differs when implemented in Groovy and Jython.

JavaFX 8 and Groovy. In this section, we’ll implement the JavaFXDraw application via the Groovy language. If you are new to Groovy, it is a very easy alternative language to start with because it allows you to code using either the standard Java syntax or the Groovy syntax, providing an environment that is easy to begin working in for any experienced Java developer. This example takes advantage of the ability to mix both Java and Groovy syntax together.

Tailor-Made

Implementing JavaFX applications with alternative languages can have advantages. There are even more advantages to using an API that is tailored specifically for use with JavaFX.

Listing 2 contains code for the entire Groovy implementation, which is a few lines shorter than the JavaFX 8 implementation. The code could have used more of the Groovy syntax, but much of the Java syntax was retained to demonstrate the benefits of mixing both Java and Groovy. For starters, note that the Groovy application still launches within the main method, and much of the code remains the same. However, the Groovy code is a bit more concise because it does not contain semicolons, since they are optional in Groovy. The Groovy code also uses closures—as opposed to Java SE 8 lambdas—which have a slightly different syntax but provide the same overall benefit.

Note: The following listing has been excerpted for space, as noted by the ... symbol. The full code listing is available by downloading the code listings for this issue.

class JavaFXDrawGroovy extends Application {
    static void main(args)
    {
        Application.launch(JavaFXDrawGroovy.class, args)
    }
    
    void start(Stage stage)
    {
        def root = new StackPane()
        def screen = Screen.getPrimary()
        def rect = screen.getVisualBounds()
        def canvas = new Canvas(rect.getWidth()/2 + 50,
            rect.getHeight()/2 + 300 )
        def graphicsContext = canvas.getGraphicsContext2D()

        def resetButton = new Button("Reset")
        resetButton.setOnAction({
                graphicsContext.clearRect(1, 1, 
                graphicsContext.getCanvas().getWidth()-2, 
                graphicsContext.getCanvas().getHeight()-2)
            } as EventHandler)
        resetButton.setTranslateX(10)

        // Set up the pen color chooser
        def colorChooser = new ChoiceBox(
         FXCollections.observableArrayList(
         "Black", "Blue", "Red", "Green", "Brown", "Orange"
        ))
…

Listing 2

Let’s take a look at the Reset button in the Groovy implementation, and compare it to the JavaFX 8 API code shown earlier. The Reset button code uses a closure to encapsulate the event handling implementation. Similarly, the canvas “mouse button pressed” event listener is implemented using a Groovy closure:

canvas.addEventHandler(
   MouseEvent.MOUSE_PRESSED, {
  MouseEvent event->
  graphicsContext.beginPath()
  graphicsContext.moveTo(
      event.getX(),
      event.getY())
  graphicsContext.stroke()
 } as EventHandler)


A few more notes about Groovy: Although the code in Listing 2 contains switch statements that compare int values, it is possible to compare any type of switch value within a Groovy switch statement. Groovy switch statements can also perform different types of matching. Groovy contains many builders, making it easier to construct objects than with standard Java. There are many more features available in Groovy, and to learn more about them, take a look at the Groovy User Guide.

It is easy (and fun) to implement JavaFX 8 applications using Groovy. However, later in this article, we’ll take a look at an even groovier way to write JavaFX using Groovy.

Note: You should use Groovy 2.3.x to ensure full compatibility with Java SE 8.

JavaFX 8 and Jython. It is said that Python allows developers to get things done without getting in the way. Python code is concise, easy to follow, and very productive. Jython is the Python language implemented for the Java Virtual Machine (JVM). Implementing JavaFX applications in Jython can be quite effective, and it is easy to translate Java to Python syntax.

Note: The code for this example was written with the beta versions of Jython 2.7 and JavaFX 8.

Listing 3 contains the complete code for our drawing application written in Jython. Note that the Jython implementation is even fewer lines than JavaFX 8 or Groovy. For starters, the application is launched a bit differently from Jython, although the same concept as the main method applies. The Jython main method looks a bit different than in the other two languages:

if __name__ == "__main__":
    …


In Listing 3, the JythonFXDraw class implements Application, per the JavaFX standard. The start method contains the same logic as with the other implementations, but it is written in the Python language syntax.

Note: The following listing has been excerpted for space, as noted by the ... symbol. The full code listing is available by downloading the code listings for this issue.

class JythonFXDraw(Application):

    def start(self, primaryStage):
        primaryStage.setTitle("JythonFX Draw")
        root = StackPane()
        screen = javafx.stage.Screen.getPrimary()
        rect = screen.visualBounds
        canvas = Canvas(rect.width/2 + 50,
                        rect.height/2 + 300)
        graphics_context = canvas.graphicsContext2D
        
        def resetAction(event):
            graphics_context.clearRect(1,1,
            graphics_context.canvas.width-2,
            graphics_context.canvas.height-2)
...

Listing 3

Again, let’s take a look at the Reset button implementation to see how it differs from the others. The event handler is written by assigning the resetAction function to the onAction property. The resetAction function contains the same logic as the others for clearing the canvas:

Button("Reset",
       onAction=resetAction)


Similarly, the canvas action listeners are implemented as functions, and then assigned to the canvas. The following code shows the “mouse pressed” listener implementation:

def mouse_pressed(event):
    graphics_context.
        beginPath()
    graphics_context.
        moveTo(event.x,
               event.y)
    graphics_context.
        Stroke()


Jython does not contain a switch statement, so the implementation for the ChoiceBox selection uses an if statement instead:

if idx == 0:
    new_color = Color.BLACK
elif idx == 1:
    new_color = Color.BLUE
elif idx == 2:
    new_color = Color.RED
…


If you are new to Python, you’ll see that there is a standard indentation structure to which you must adhere. That said, the code is concise and easy to follow. Another note about Jython is that, just as in Groovy, there is no need to declare types, so function parameters and variables are typeless.

Using Custom APIs to Develop JavaFX Applications

We’ve already seen that implementing JavaFX applications with alternative languages can have advantages. While there are some advantages to coding with alternative languages, there are even more advantages to using an API that is tailored specifically for use with JavaFX. In this section, we will take a look at the GroovyFX API, which completely changes the way in which a developer can construct a JavaFX application. The developers of GroovyFX have made it easy to visually see the scene graph as it is being built, making code easier to read, understand, and visualize.

GroovyFX at a glance. GroovyFX is an API that allows you to construct a JavaFX application using the Groovy builder syntax. The resulting code is very clean and easy to read, making the construction of JavaFX applications very easy. GroovyFX also eliminates lots of boilerplate code, allowing you to concentrate on what you’d like to get done, rather than on worrying about specific API calls. This is possible because GroovyFX takes advantage of Groovy’s powerful domain-specific language (DSL) features and abstract syntax tree (AST) transformation.

Let’s begin by transforming the application that was written in the first section of this article using Groovy and Jython so it adheres to the GroovyFX API. Listing 4 contains the code for the GroovyFXDraw application. The code is significantly shorter than any of the other code we’ve looked at thus far. It is also easy to read because it uses the Groovy builder pattern.

Note: The following listing has been excerpted for space, as noted by the ... symbol. The full code listing is available by downloading the code listings for this issue.

import static groovyx.javafx.GroovyFX.start
import groovyx.javafx.beans.FXBindable
import javafx.stage.Screen
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color
import javafx.collections.FXCollections
import javafx.scene.canvas.Canvas
import javafx.scene.canvas.GraphicsContext
import javafx.stage.Screen

start {
    stage(title: 'GroovyFX Draw', visible: true) {
        scene = scene(id: "sc", fill: WHITE, 
            width: Screen.getPrimary()
                .getVisualBounds().getWidth(),
            height: Screen.getPrimary()
              .getVisualBounds().getHeight()) {

            canvas = canvas(id: "drawcanvas",
                width: bind(sc.width()),
                height: bind(sc.height()))
            GraphicsContext graphicsContext =
              canvas.graphicsContext2D
            canvas.onMousePressed { 
                MouseEvent event->
                graphicsContext.beginPath()
                graphicsContext.moveTo(event.getX(),
                                       event.getY())
                graphicsContext.stroke()
            } 
...

Listing 4

Another significant difference is the way in which the application is launched, because no main method is defined. Instead, a Groovy closure that contains the application constructs is simply passed to the static groovyx.javafx.GroovyFX.start method to initiate the application:

start {
  // Declare JavaFX
  // scene graph nodes
}


An additional important difference is the way in which the code is constructed. Each node embedded into the scene graph is constructed as a Groovy closure, and in some cases nodes are embedded within each other. This visual syntax provides an easy way to see how the user interface will be laid out. The properties of each node are also specified differently with GroovyFX, because they are treated as key/value pairs. Each node can have its own set of properties specified by placing them within a comma-separated key/value format, as seen here:

hbox(spacing:10, padding:10) {
…


Getting started with GroovyFX.
There are a couple of easy steps you need to take before you can use GroovyFX. To use GroovyFX in any environment (without the use of an IDE), first, download GroovyFX using the latest distribution from the GroovyFX site. Alternatively, you can build the GroovyFX Project from the source code by cloning the project from GitHub.

To clone the project, ensure that you have Git installed on your system, and then clone the project by executing the following command:

git clone git://github.com/
groovyfx-project/groovyfx.git. 

Note: Please ensure that you are using GroovyFX 0.4.0 for Java 8 and JavaFX 8 compatibility. The examples for this article were written with GroovyFX 0.3.1 and Java SE 7, as GroovyFX 0.4.0 was not available at the time.

Once you’ve cloned the project, you can build it from source code using Gradle. The current release, 0.4.0, includes support for JavaFX 2.2 on Java 7 or JavaFX 8 on Java 8.

git clone -b 0_4_SNAPSHOT git:// 
github.com/groovyfx-project/ 
groovyfx.git

cd <<groovyfx_location>>
gradlew build


You can then run any of the packaged examples using the gradlew command, followed by the name of the example. For example, to run HelloWorldDemo, use the following command:

gradlew HelloWorldDemo


If you prefer to use an IDE such as NetBeans, simply clone the GroovyFX project and open it within NetBeans. By default, the GroovyFX project distribution is a NetBeans IDE project. You can run any of the demos within the NetBeans IDE by expanding the Demo Programs folder, right-clicking the demo, and choosing Run. There are some excellent GroovyFX examples contained in the distribution. If you wish to use an IDE other than NetBeans, you can refer to the GroovyFX Guide for details.

Building a basic GroovyFX application. As mentioned previously, all GroovyFX applications are launched using the static groovyx.javafx.GroovyFX.start method. The scene graph is passed to the start method by enclosing it within brackets. We’re able to use the Groovy builder syntax, but behind the scenes, GroovyFX’ SceneGraphBuilder is used to construct the scene graph.

Easy Does It

JavaFX 8 makes it easy to develop animations, and GroovyFX makes it even easier!

Each of the JavaFX controls is available to GroovyFX, but the syntax is a bit different than usual. For instance, each of the controls when used in Java code begins with a capital letter. However, its GroovyFX counterpart must begin with a lowercase letter.

Another difference is that instead of using Java “setters” to configure different control properties, GroovyFX allows you to pass a map (key/value pairs) of different properties to be set. Take, for instance, the JavaFX Button control. In JavaFX, the control must be instantiated and then set to different properties, and setter methods must be called upon the Button instance. In GroovyFX, a Button control is instantiated by placing it within the Scene closure, and different properties are set by enclosing them as key/value pairs within parentheses, as follows:

button("Save", 
  style:"-fx-font: 14 arial", 
   onAction: {
   textEntry = 
      text.getText()
      println textEntry
})


Note that the event handler is written inline as a Groovy closure, and it is assigned to the onAction property. Styles are set inline as well using the style property. You can also access the javafx.scene.text.Font directly as a node property. For example, the style property from the previous example could be changed to font: '14pt arial', as follows, instead of listing out the full style string:

button("Save", 
   font: '14pt arial', 
   onAction: {
   textEntry = 
      text.getText()
      println textEntry
})


The code in Listing 5 includes this Button control, along with a TextField and Label. The basic application allows you to enter some text into the TextField, click the button, and have the text printed to the server log file. It is a very simple application, but you can see that it demonstrates basic layout with GroovyFX, and it uses an HBox. In this example, the HBox contains the label and the TextField, with a spacing of 5.

hbox(spacing: 5){
   ...
}

 

import static groovyx.javafx.GroovyFX.start

start{
    def textEntry;
    stage(title: "GroovyFX Introduction", width: 600,
          height: 300, visible: true){
        scene(fill: groovyblue){
            hbox(spacing: 5){
                label("Place Text Here:",
                      textFill: white,
                      halignment: center,
                      valignment: center)
                text = textField(promptText: "Type here",
                       prefColumnCount: 25)
            }
                button("Save", style:"-fx-font: 14 arial", 
                       onAction: {
                       textEntry = text.getText()
                       println textEntry
                })
            
        }
    }
}

Listing 5

In addition, colors and paints can be set using either the JavaFX Paint or Color objects, or via pseudo color variables (RED, ORANGE, GREEN, and so on). Colors can even be defined as a hex string or a JavaFX cascading style sheet (CSS) style, making GroovyFX very flexible. GroovyFX includes a multitude of handy shortcuts; to learn about them, I recommend taking a look at the GroovyFX documentation.

Abstracting inline code. Additional code can be placed outside the scene graph, and it will still reside within scope for use via scene graph nodes. Listing 6 demonstrates an example of placing code outside the scene graph in an effort to organize. The code in Listing 6 is for the GroovyFXDraw application, but the Button control for resetting the Canvas has had its event handler code abstracted and placed within a closure that has been defined outside the scene graph.

import static groovyx.javafx.GroovyFX.start
import groovyx.javafx.beans.FXBindable
import javafx.stage.Screen
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color
import javafx.collections.FXCollections
import javafx.scene.canvas.Canvas
import javafx.scene.canvas.GraphicsContext
import javafx.stage.Screen

def reset = { graphicsContext ->
    graphicsContext.clearRect(1, 1, 
    graphicsContext.getCanvas().getWidth()-2, 
    graphicsContext.getCanvas().getHeight()-2)
}

start {
    ...
              
            hbox(spacing: 10, padding: 10) {
                button("Reset",
                onAction: {reset(graphicsContext)})
                …
                }
                ...
}

Listing 6

This style of coding for GroovyFX applications can come in very handy when working with large scene graphs that contain many events. It also can be handy if you want to make a class accessible within your scene graph, but still place it within the same Groovy file.

Other Options

Although the JavaFX 8 API is very nice, there are advantages to knowing more than one way to develop a JavaFX application.

Binding properties with GroovyFX. One of the most powerful features of JavaFX is its binding ability. Binding allows nodes within a scene graph to exchange data and react together in real time. For instance, if the text property of a TextField control is bound to a Label, then the Label text will reflect any changes that are made to the TextField contents as a user is typing. JavaFX binding can contain lots of boilerplate code, and GroovyFX reduces the boilerplate by using its bind utility. The following Label written in GroovyFX demonstrates binding to a TextField named text.

Label(text:bind(text, 'text'))


The code in Listing 7 demonstrates simple binding using this technique. When the code is executed, the Label will mirror any text typed into the TextField (see Figure 2).

String textEntry
start{
    
    stage(title: "GroovyFX Introduction", width: 600,
        height: 300, visible: true){
        scene(fill: groovyblue){
            gridPane(hgap: 5, vgap: 10,
                     padding: 20){
                hbox(spacing: 5, row:1,
                     columnSpan:2 ){
                    label("Place Text Here:",
                          textFill: white,
                          halignment: center,
                          valignment: center)
                    text = textField(
                            promptText: "Type here",
                            prefColumnCount: 25)
                }
               
                button("Save", font: "14pt arial",
                        row: 2, column: 1, 
                    onAction: {
                        textEntry = text.getText()
                        println textEntry
                    })
                label(text: bind(text, 'text'),
                       row: 3, column: 1)
            }
        }
    }
}

Listing 7

RichClient-f2

Figure 2

GroovyFX also provides a convenience annotation, @FXBindable, to automatically mark a property or entire class as bindable. By applying the @FXBindable annotation to a property or class, the binding logic will be automatically added to the code at runtime, alleviating the need to write redundant boilerplate code.

In the next example, a simple form has been generated for entering car information (see Figure 3). The form fields are each bound to fields within a Car object. The form button adds the current Car object to a List of Car objects, and the current List size is automatically incremented and displayed as a Label on the form. Take a look at Listing 8 to see the code for this example.

RichClient-f3
Figure 3

Note: The following listing has been excerpted for space, as noted by the ... symbol. The full code listing is available by downloading the code listings for this issue.

@FXBindable
class Car{
    String make
    String model
    String year
    String description
}

@FXBindable
class CarHotel{
    
  List<Car> carList = new ArrayList()
  Car car = new Car()
  String carCount 
    
  def addCar(car){
      print "Adding car: ${car.make}"
      carList.add(car)
      carCount = "The number of cars is: ${carList.size()}"
      car = new Car() 
    }

}
…

Listing 8

Animation with GroovyFX. Now, I am primarily an enterprise developer . . . so animation is not my forte. However, JavaFX 8 makes it easy to develop animations, and GroovyFX makes it even easier! Animations occur on a timeline, and different activities can occur within the span of the timeline.

Learn More


 Introducing GroovyFX: It’s About Time

 Jython website

In this example, the timeline contains two simple change effects that occur indefinitely, beginning at 1,000 milliseconds. This example animates a circle and a line to create a yo-yo effect (see Figure 4). Therefore, the circle is changed every 1,000 milliseconds to move from its starting centerY value of 60 to a centerY value of 340. Similarly, the line is changed every 1,000 milliseconds to expand from its starting Y value of 0 to an ending Y value of 280, and then back again. To make the example even more fun, I added some fading text, which fades from 0 opacity to 1 over a specified time span.

RichClient-f4

Figure 4

To see the code for the animation example, see Listing 9.

Note: The following listing has been excerpted for space, as noted by the ... symbol. The full code listing is available by downloading the code listings for this issue.

import static groovyx.javafx.GroovyFX.start
start {
    stage(title: "GroovyFX YoYo", width: 500,
        height: 400, visible: true) {
        scene(fill: GROOVYBLUE) {
            circle = circle(centerX: 250,
                centerY: 60,
                radius:60,
                fill: WHITE,
                stroke: BLACK){
                effect: boxBlur(10, 10, 3)
            }
            line   = line (startX: 250,
                endX: 250,
                startY: 0,
                endY: 0,
                strokeWidth: 3)
            myTxt = text("Groovy!",
                x:  200, y: 150, fill: ORANGE,
                font: "bold 26pt Arial"){
                  fade = fadeTransition(
                              duration: 5000.ms,  
                              fromValue: 0.0,
                              toValue: 1.0)
                  effect dropShadow(offsetY: 4)
                }
        }
    }
...

Listing 9

FXML support. Placing view code into FXML files is a recommended approach for separating view code from business logic for JavaFX applications. GroovyFX supports the use of FXML by referencing the files via an fxml node within the scene graph:

scene {
fxml(new File('./myfxml.fxml')
 .text)
… 


Other Alternative APIs

Other alternative languages, such as JRuby and Scala, can be used to develop JavaFX applications as well. In fact, these two languages, in particular, have their own specialized APIs for JavaFX development: JRubyFX and ScalaFX, respectively. These APIs are similar to GroovyFX in that they provide an easy way to work with the JavaFX API in the alternative language syntax. For more information, check out their project websites.

Conclusion

JavaFX 8 contains a bevy of new features, and the ability to make use of Java SE 8 constructs, such as lambdas and streams, makes JavaFX development even easier. Alternative languages can provide benefits over—and in some cases work hand in hand with—the JavaFX API. In some cases, alternative languages have their own DSLs for developing JavaFX, which can be even more productive and easy to use.

Add a new tool to your JavaFX toolbox today by learning an alternative approach to developing JavaFX applications.


juneau-headshot




Josh Juneau
is an application developer, system analyst, and DBA who uses Java, PL/SQL, and Jython/Python. He manages the Jython Monthly newsletter, Jython Podcast, and the Jython website. He authored Java EE 7 Recipes (Apress, 2013) and Introducing Java EE 7 (Apress, 2013), and is working on Java 8 Recipes, which Apress will publish later this year.