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”.
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.
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.
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.
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.
Set the name of the FXML file to HelloWorldScene, and set the Root Element to AnchorPane. Then, click the Finish button.
Now your HelloWorld project should have the following files.
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.
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.
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.
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.
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.
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.
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.
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”.
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.
Your controller code should read as follows.
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.
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.
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.
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.
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.