JavaFX 8 Hello World for Eclipse

Learning JavaFX 8 on Eclipse is simple, once you get past the first Hello World style example. This JavaFX tutorial introduces SceneBuilder, FXML, and JavaFX 8 for Eclipse with an event (an ActionListener) and a controller class.

Believe it or not, I have a JavaFX 8 book that never once explains how to hook up events between a POJO and FXML generated from SceneBuilder—hundreds of pages of how-to material on JavaFX, and not one word on events. Pretty sad.

No such letdown here.

This tutorial demonstrates and explains creating a window that displays a button and a textfield in JavaFX 8, and then hooking them up in Eclipse, using SceneBuilder, so that clicking the button results in the words “Hello World” displaying in the textfield.

Prerequisites: You will need to install Java 8, SceneBuilder 8 and a version of Eclipse with JavaFX capabilities to do this tutorial.

Creating a JavaFX Project in Eclipse

The first step to creating a JavaFX Hello World is to create a basic JavaFX Project. You can do this in a similar way as you would create any Java Project.

From the Eclipse menu, select File->New->Other… Expand the JavaFX folder and select the JavaFX Project and click the Next> button. In the properties dialog that pops up, set the project name to “HelloWorld”.

New JavaFX 8 Project
Select the JavaFX Project to create a new JavaFX 8 project.

After you finish creating the JavaFX project, look at the Eclipse Package Explorer. The Package Explorer is usually configured to be on the left side of the Eclipse window.

In the Package Explore, you now have a rudimentary JavaFX 8 project named HelloWorld. Your JavaFX 8 project has the JavaFX SDK, and a source file named Main.java.

JavaFX 8 Project in Package Explorer
The initial JavaFX 8 project as seen in the Eclipse Package Explorer.

The source code for Main.java is pretty basic stuff with some JavaFX goodies thrown in. Notice, the Main class extends javafx.application.Application. No surprise. Application is part of JavaFX. Application requires your Main class to override the start() method.

Don’t worry about the contents of the start() method, yet. We’ll be rewriting them, soon. We’ll go over that code when we get to it.

Notice the traditional Java main() method is present, but only calls launch(). JavaFX programs only have that one line of code in their main() methods. Put your startup code in the start() method, never in the main() method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package application;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) {
    try {
      BorderPane root = new BorderPane();
      Scene scene = new Scene(root, 400, 400);
      scene.getStylesheets().add(getClass()
          .getResource("application.css")
          .toExternalForm());
      primaryStage.setScene(scene);
      primaryStage.show();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args) {
    launch(args);
  }
}

JavaFX heavily encourages MVC or MVP design pattern use. I’ll let someone else argue whether there is any difference between MVC and MVP other than semantics. For our purposes, the controller (or presenter) is going to be in HelloWorldController.java. Go ahead and create a new Java class named HelloWorldController in the same package as the Main class.

Once you create the HelloWorldController class, it probably has source that looks like the following source code. It doesn’t matter. We’ll be replacing it soon with a skeleton created by SceneBuilder 8.

1
2
3
4
5
package application;

public class HelloWorldController {

}

The last file we need is an FXML document. The FXML file will serve as our scene. I’ll explain scenes below.

From the Eclipse menu, select File->New->Other… Expand the JavaFX folder and select New FXML Document. Then click the Next> button.

New FXML Document
The new FXML document will have almost no FXML in it.

Set the name of the FXML file to HelloWorldScene, and set the Root Element to AnchorPane. Then, click the Finish button.

FXML File Settings
Set the name of the FXML file to HelloWorldScene, and the Root Element to AnchorPane.

Now your HelloWorld project should have the following files.

Base JavaFX 8 Project with FXML File
All the necessary FXML and JavaFX 8 files are now present in Eclipse’s Package Explorer.

If you open up the HelloWorldScene.fxml file, you will see the following FXML. Looking at the FXML file may feel eerily similar to looking at Java, except Java mutated by a mad scientist into some XML-Java hybrid. The FXML has an import for the AnchorPane class, and consists entirely of one UI element, a container called an AnchorPane.

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.AnchorPane?>

<AnchorPane xmlns:fx="http://javafx.com/fxml/1">
	<!-- TODO Add Nodes -->
</AnchorPane>

Modifying FXML with SceneBuilder

JavaFX programs organize there UI elements into a tree with a root node called a stage. The stage is what Swing developers call a Window. The Stage is provided as a parameter to the start() method in our Main class. Under the root node is a scene. Scenes can be swapped out with different scenes just by calling the setScene() method on the Stage object.

JavaFX Stage, Scene, Group, and Leaf Node
JavaFX organizes its UI into Stages, Scenes, Groups, and Leaf Nodes.

Scenes have groups and terminal nodes (also called leaf nodes.) Groups and scenes are containers, such as the AnchorPane. Groups may be nested in other groups when creating complex UI’s. Terminal nodes are buttons, labels, textfields, drawn shapes, or other non-container GUI elements.

We’re at the point where we can flesh out our simple UI. We could do so by entering our FXML into HelloWorldScene.fxml by hand, but that defeats the whole point of having a RAD tool like SceneBuilder. SceneBuilder takes care of layout, UI previews, setting up events, and creating skeleton code for our controller class (HelloWorldController.java). So we’re going to take advantage of it.

Open HelloWorldScene.fxml in SceneBuilder 8. If you have configured Eclipse to open SceneBuilder, you can do it from Eclipse. Otherwise, open SceneBuilder and browse to the file to open it.

In reality, we did not have to create the FXML file from an Eclipse template, we could have created it from scratch in SceneBuilder, and then imported the file into Eclipse. Just make sure the FXML files are saved in the correct place in the package structure when you create them directly from SceneBuilder.

If you’ve ever used a RAD tool for UI development, SceneBuilder will look familiar to you. SceneBuilder looks like your typical RAD tool for UI development, except this one is all about FXML and JavaFX 8.

SceneBuilder 8
Our FXML scene opened in SceneBuilder 8.

The AnchorPane is the only UI element in HelloWorldScene, so far. Unfortunately, the default size is too small to be of any use to us, currently. We need to change the preferred size settings, so the AnchorPane is large enough to work with.

SceneBuilder Size Properties
Selecting an item in the SceneBuilder Hierarchy allows for size changes in the item’s layout.

To change the preferred size of the AnchorPane, select the AnchorPane in Hierarchy on the left side of SceneBuilder. Then, select the Layout on the right side of SceneBuilder. Scroll to the Size section of the Layout, and change “Pref Width” to 600 and “Pref Height” to 400. Now you should see an AnchorPane that is usable.

JavaFX AnchorPane Resized
By resizing the JavaFX AnchorPane, we can now more easily position containers or controls on it.

For this example, we only need a TextField and a Button. You will find both of these elements under the Controls on the left side of SceneBuild. Just drag them onto the newly resized AnchorPane in the middle of the screen and position the TextField and Button to your liking.

Button and TextField in JavaFX AnchorPane
Now you have a Button and a TextField in a JavaFX AnchorPane.

While positioning the UI elements, you may notice red lines appearing and disappearing. These are hints that let you easily position elements in relation to other elements or centering the elements on the screen.

To change the text on the Button after you have positioned it on the AnchorPane, double-click the button. You will be able to edit the Button text at that point. I changed my Button text to read, “Say Hello”. You can change yours to whatever you like.

Once your Button and TextField are positioned on the AnchorPane, look at the Hierarchy on the left side of SceneBuilder. You will notice that the new elements are now displayed under the AnchorPane. The AnchorPane is your scene, and the Button and TextField are leaf nodes. We did not bother with a group between the scene and leaf nodes for this tutorial.

SceneBuilder Code Area
Set the fx:id and On Action for the button in SceneBuilder.

Next up, open the Code section on the righthand of SceneBuilder. We need to give our leaf nodes (AKA Button and TextField) identities and define the ActionListener for our Button. These properties will be translated into variables and a method when we create the skeleton code for our controller.

Select “Button” under the Hierarchy section on the right side of SceneBuilder. The Code section on the righthand side of SceneBuilder should now display code related properties for your button. Set the fx:id to “helloBtn” and set the On Action to “sayHello”.

Select your TextField from the Hierarchy and change its fx:id under Code to “helloTF”.

Finally, we need to set our Controller for the FXML file. This used to be done programmatically, but JavaFX 8 allows this to be done from the FXML we create in SceneBuilder.

Open the Controller section at the bottom of the left side of SceneBuilder. The Controller section already has our Button and TextField fx:id’s displayed. We need to add the Controller class property. Set the controller to the fully qualified name of our controller. That is “application.HelloWorldController”.

SceneBuilder Controller Class Property
JavaFX 8 allows the FXML’s controller class property to be set from SceneBuilder 8.

Don’t forget to save your changes to your FXML file!

 

Hooking Up Events to the Controller

You are finished laying out your JavaFX 8 Hello World application’s UI. If you want to preview your FXML from SceneBuilder, navigate to Preview->Show Preview in Window in the SceneBuilder menu. This allows you to see what the HelloWorldScene.fxml looks like in a window. However, the Button and TextField are not hooked up to any code yet. So, they just sit there doing nothing when you click the Button.

Now it’s time to get into the code for our controller. Start by navigating to View->Show Sample Controller Skeleton in the SceneBuilder menu. This pops up a window with some starting code for our controller class. Select “Comments” and unselect “Full” at the bottom of the window. Then copy the code by clicking the “Copy” button and paste the code into the HelloWorldController class in Eclipse.

JavaFX Controller Class Skeleton Code
Get the FXML’s controller class skeleton code from SceneBuilder 8.

Your controller code should read as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * Sample Skeleton for 'HelloWorldScene.fxml' Controller Class
 */

package application;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;

public class HelloWorldController {

    @FXML // fx:id="helloBtn"
    private Button helloBtn; // Value injected by FXMLLoader

    @FXML // fx:id="helloTF"
    private TextField helloTF; // Value injected by FXMLLoader

    @FXML
    void sayHello(ActionEvent event) {

    }

}

This code is missing an import and doesn’t do anything in the sayHello() method. Fix that by changing the code to match the following.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * Sample Skeleton for 'HelloWorldScene.fxml' Controller Class
 */

package application;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;

public class HelloWorldController {

    @FXML // fx:id="helloBtn"
    private Button helloBtn; // Value injected by FXMLLoader

    @FXML // fx:id="helloTF"
    private TextField helloTF; // Value injected by FXMLLoader

    @FXML
    void sayHello(ActionEvent event) {
      helloTF.setText( "Hello World!" );
    }

}

You should recognize a lot of the names in the controller class as values we set in SceneBuilder. The package is set, because we used the fully qualified class name for our controller in SceneBuilder. The Button and TextField names are taken from the fx:id values we set in the code area of SceneBuilder, and the action listener (to use Swing terminology) is named after the On Action property we set in SceneBuilder.

Notice that all the imports are from the javafx packages. Also, notice the @FXML annotations used to tell the compiler and JVM to hook up the FXML elements. The values for helloBtn and helloTF are supplied by dependency injection at runtime by the call to FXMLLoader in the Main class’s start() method. We haven’t written that code yet, but we are now ready to finish our Main class.

Modify your Main class to read as follows.

package application;

import java.io.IOException;
import java.net.URL;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) throws IOException {
    
    // constructing our scene
    URL url = getClass().getResource("HelloWorldScene.fxml");
    AnchorPane pane = FXMLLoader.load( url );
    Scene scene = new Scene( pane );
    
    // setting the stage
    primaryStage.setScene( scene );
    primaryStage.setTitle( "Hello World Demo" );
    primaryStage.show();
    
  }

  public static void main(String[] args) {
    launch(args);
  }
}

The main change is to the imports and the start() method. In the start() method, we begin by loading the FXML scene using the FXMLLoader’s load() method. FXML takes a URL as it’s argument, so we use the current ClassLoader to get the URL for the HelloWorldScene.fxml file. Then, we construct the scene from the resulting AnchorPane.

The reason FXMLLoader’s load() method creates an AnchorPane is because that is the root of the hierarchy we had in SceneBuilder. If the root not in SceneBuilder had been another container type, then that is the type of pane we would be get back from the load() method, and the type of object we would use to construct the Scene object with.

After we have a Scene object, it is trivial to set the stage’s scene, give it a title, and call show(). That’s all there is to our basic JavaFX 8 app.

Remember: You changed your FXML file from an external source (SceneBuilder), so select the file in Package Explorer in Eclipse and refresh the source by hitting the F5 key. The HelloWorldScene.fxml file should read as follows when refreshed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40" fx:controller="application.HelloWorldController">
   <children>
      <Button fx:id="helloBtn" layoutX="263.0" layoutY="223.0" mnemonicParsing="false" onAction="#sayHello" text="Say Hello" />
      <TextField fx:id="helloTF" layoutX="219.0" layoutY="107.0" />
   </children>
</AnchorPane>

You can look at the FXML source if you’re curious, but SceneBuilder does all the FXML work for us, so you don’t need to know the details.

JavaFX 8 Hello World
JavaFX 8 Hello World demo stage and scene.

Now you can run your JavaFX 8 Hello World from Eclipse as a Java Application. Select the HelloWorld project in Package Explorer, and then from the Eclipse menu select Run->Run As->Java Application and your JavaFX 8 Hello World should pop up in its own window.

Now that you have your first Hello World for JavaFX 8 complete, creating fullfledge apps in JavaFX 8 will come pretty easy, especially, if you have previous Swing or AWT experience.