Building Applications in JavaFX 2.0

by Daniel Zwolenski

In a series of innovative blog postings, Downstream's Senior Java Architect Daniel Zwolenski explores ways to build applications in JavaFX 2.0 -- from Spring to controller injection to client servers.

Published February 2012

Downloads:
Download: JavaFX 2.0
Download: JFX Flow

Note: JFX Flow is a free, open source framework for developing rich, interactive and user friendly web-style GUIs for desktops using JavaFX (2.0+). JFX Flow combines the powerful feature set of JavaFX (styling, animations, FXML, etc.) with a simple “web flow” style framework that is easy to use and that fosters clean architectural patterns, especially when developing Java EE applications. JFX Flow is currently in Alpha release and may still have some bugs. The core framework is usable however, and the API is quite stable.

Introduction

In this article, the first of several in which I explore various options for building applications in JavaFX 2.0, I perform a direct port of Richard Bair’s FXML+Guice dependency injection example into Spring. (Richard Bair is Oracle’s Chief Architect for the Client Java Platform.) Many developers still believe that Spring is all about XML configuration files, but it has evolved a lot since the early days. I’m going to use Spring’s annotation-based configuration to create a pure Java example (i.e., zero Spring XML) that looks almost identical to the Guice one.

Step 1: Create a Person Bean

public class Person
{
    private String firstName;
 
    public Person(String firstName)
    {
        this.firstName = firstName;
    }
 
    public String getFirstName()
    {
        return firstName;
    }
}

Listing 1. Creating a Person Bean

Step 2: Create a SampleController

This is similar to Richard Bair’s – however, instead of using Guice’s @Inject annotation, we use Spring’s @Autowire one (I’ve annotated the parameter but you could use constructor injection if you want):

import org.springframework.beans.factory.annotation.Autowired;
 
public class SampleController
{
    @Autowired
    private Person person;
 
    public Person getPerson()
    {
        return person;
    }
 
    public void print()
    {
        System.out.println("Well done, " + person.getFirstName() + "!");
    }
} 

Listing 2. Creating a SampleController

Step 3: Create the FXML File

This is identical to Bair’s, except I used the getPerson().getFirstName() instead of a getPersonName() -- he could have done the same, there’s no real difference on this.

<?xml version="1.0" encoding="UTF-8"?>
 
<?language javascript?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
 
<StackPane fx:id="root" xmlns:fx="http://javafx.com/fxml">
    <children>
        <Button fx:id="printBtn" onAction="controller.print()" />
        <fx:script>printBtn.text = 'Click Me ' + controller.getPerson().getFirstName() + '!';</fx:script>
    </children>
</StackPane>

Listing 3. Creating the FXML File

Step 4: Create a Spring Application Context

Here’s where things start to get interesting. Instead of the Guice “Module” we need to define a Spring equivalent. In this case I have defined a class called SampleAppFactory (but you can call it anything) – the important bit is that it is annotated with Spring’s @Configuration. Each of the methods that are then annotated with @Bean belong to the context and Spring can do magic wiring for us. In our case, the SampleController will get wired up with the Person because of the @Autowired annotation on it.

For anyone used to Spring XML, this class is pretty much a direct replacement of the XML configuration file: 

import org.springframework.context.annotation.Configuration;
 
@Configuration
public class SampleAppFactory
{
    @Bean
    public Person person()
    {
        return new Person("Richard");
    }
 
    @Bean
    public SampleController sampleController()
    {
        return new SampleController();
    }
}

Listing 4: Create a Spring Application Context

Step 5: Build a Custom FXML Loader

We can easily build the Swing equivalent of Bair’s GuiceFXMLLoader. It just needs to load the controller from the application context instead of the Guice Injector. In another blog post, I look at how we can simplify this and clean things up a little.

import javafx.fxml.FXMLLoader;
import org.springframework.context.ApplicationContext;
 
import java.io.IOException;
import java.io.InputStream;
 
public class SpringFxmlLoader
{
    private ApplicationContext context;
 
    public SpringFxmlLoader(ApplicationContext context)
    {
        this.context = context;
    }
 
    public Object load(String url, Class<?> controllerClass) throws IOException
    {
        InputStream fxmlStream = null;
        try
        {
            fxmlStream = controllerClass.getResourceAsStream(url);
            Object instance = context.getBean(controllerClass);
            FXMLLoader loader = new FXMLLoader();
            loader.getNamespace().put("controller", instance);
            return loader.load(fxmlStream);
        }
        finally
        {
            if (fxmlStream != null)
            {
                fxmlStream.close();
            }
        }
    }
}

Listing 5: Building a Custom FXML Loader

Step 6: Create an “Application” to Launch it All

This is quite similar to the Guice approach, except we load our application context instead of the Guice injector:

import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
public class SampleApp extends Application
{
    public static void main(String[] args)
    {
        launch(args);
    }
 
    public void start(Stage stage) throws Exception
    {
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(SampleAppFactory.class);
        SpringFxmlLoader loader = new SpringFxmlLoader(context);
 
        Parent root = (Parent) loader.load("/sample.fxml", SampleController.class);
        Scene scene = new Scene(root, 320, 240);
        scene.getStylesheets().add("/fxmlapp.css");
        stage.setScene(scene);
        stage.setTitle("JFX2.0 Sprung");
        stage.show();
    }
}

Listing 6: Creating an “Application” to Launch it all

That’s it! As you can see, the code is quite similar to Guice, so the choice between Guice and Spring should depend on the other features offered by each and how these may benefit you. In subsequent article postings, I stick with Spring, but much of what I present could easily be adapted back to Guice.

See Also


About the Author

Daniel Zwolenski (aka “Zonski”) is a Software Architect based in Brisbane, Australia, with a passion for developing user-friendly, graphical applications in Java. He believes that building good-looking, simple user interfaces is just as important for an application as bug-free code and optimized database queries. He currently works for a small but innovative startup called Downstream developing cutting-edge safety systems for the heavy industries sector (energy, mining, chemicals, etc). He develops systems that will save lives and reduce damage to the environment due to accidents on large sites.