JavaFX

JavaFX is a framework for creating graphical applications in Java. JavaFX was a part of the JDK until Java 11, when Oracle split it off.

Install JavaFX or Not?

If you are using Java 8, 9, or 10 then JavaFX is included in the JDK.

If you are using Java 11 you need to download JavaFX from:

https://gluonhq.com/products/javafx - download JavaFX 11 (LTS version) and the documentation.

Define a Library for your IDE (Java 11+)

For Java 8-10, JavaFX is part of the JDK so you don’t need to do anything.

These instructions are good. They show you how to define a “library” in the IDE, which is something you should know how to do.

JavaFX and Eclipse use the instructions for Non-modular projects. Use JavaFX 11, not JavaFX 14.

JavaFX and IntelliJ use the instructions for Non-modular projects. Use JavaFX 11.

JavaFX and Netbeans use the instructions for Non-modular projects. Some very good tutorials on the web:

Learning JavaFX

Getting Started on openjfx.io.

JavaFX Tutorial at code.makery, 7-part series

JavaFX and SceneBuilder Tutorial by Vojtech Ruzicka.

openjfx.io the home for JavaFX information. There are many impressive examples of what is possible.

gluonhq.com provides the reference implementation for JavaFX.

Official JavaFX Tutorial (old but still accurate)

The Online Tutorial by Oracle.

  • JavaFX programming model: how a UI is constructed from objects
  • UI Components, esp. Controls
  • Layout which are how you position components in a window
  • Handling Events

JavaFX and Modules

Java 9 added modules to Java and divided the entire JDK into modules. Modules help professional developers create smaller, more modular apps, but for learners that add some complexity. Modules are different from “packages”. You can see all the modules in the JDK by typing java --list-modules.

In your applications, don’t use modules. In Eclipse or IntelliJ, when you create a new project simply do not create the module info file. Then Java will not crequire you to declare modules.

When compiling and running a JavaFX application, you may need to [add JavaFX modules][https://openjfx.io/openjfx-docs/#install-javafx] to the “Module Path”. This can be done inside your IDE (Eclipse, IntelliJ, …) or on the command line.

MacOS/Linux:

export JAVAFX_HOME=/path/to/javafx/lib
javac --module-path $JAVAFX_HOME --add-modules javafx.controls,javafx.fxml HelloWorld.java
# Run the application
java --module-path $JAVAFX_HOME --add-modules javafx.controls,javafx.fxml HelloWorld

Windows:

set JAVAFX_HOME="\path\to\javafx\lib"
javac --module-path %JAVAFX_HOME --add-modules javafx.controls,javafx.fxml HelloWorld.java
# Run the application
java --module-path %JAVAFX_HOME --add-modules javafx.controls,javafx.fxml HelloWorld

Shortcut for Command Line Options

Save typing by putting command line options in a file. Here is how.

  1. In your project root directory create a file. I used the name jvmopts but any name will work. Put the java command line args in it:
    --module-path /path/to/javafx/lib --add-modules javafx.controls,javafx.fxml 
    
  2. When you invoke Java use the @filename notation to refer to the file:
    java @jvmopts HelloWorld
    

Using FXML

Instead of writing Java code to create a UI, you can define the layout (declaratively) in a file. In JavaFX, this is an FXML file – a kind of XML. Android and Windows .Net Framework also use XML files for UI layout.

You don’t need to know the syntax of FXML!
Use SceneBuilder graphical UI edtor to create FXML and set component properties.

Connecting FXML components to Code: the Controller Class

JavaFX will create the UI from an FXML file, including all the components (Buttons, Panes, TextField, etc). But your code needs to reference those objects so you can get values and handle events.

There are 3 parts to doing this:

  • create a Controller class. In this class you define variables for the components from FXML that you want to access.
  • annotate those variables with @FXML. But do not create objects!
  • using SceneBuilder, specify the Controller class and add an id to each component that relates to a variable in the Controller

Then JavaFX will take care of making your Controller variables refer to the components created from the FXML file.

Follow these steps.

  1. For each UI component (created from FXML) you want to reference in the controller, define an attribute with an @FXML annotation:
    public class GreeterController {
         @FXML
         Button submitButton;
         @FXML
         TextField inputField;
    
  2. In the FXML file (using SceneBuilder) set the fx:id of the component to the field name in your Controller class (submitButton or inputField).
    • Be careful that the names match exactly!
    • If names don’t match, you won’t get an error from compiler, but may get a run-time error.

Defining Event Handlers

This is covered in a separate file and slides.

Example Application Launcher – for UI defined in code

Your “main” or “application” class should extend javafx.application.Application.

public class Demo extends Application {
	// Declare components that your app needs a reference to
	// Not necessary to declare every component as an attribute! 

	/**
	 * @param stage is the primary stage (a Window)
	 */
	public void start(Stage stage) {
		
		// 1. create components and layouts (Panes) for the application
		Label Label = new Label("Hello, Nerd");
		inputField = new TextField( );
		FlowPane pane = new FlowPane(label, nameField);

        // add components to the root node (container)
        pane.getChildren.addAll( label, inputField );

		// 2. create a Scene to show your pane and components
		//    The top level (root) element should be a subclass of Parent
		Scene scene = new Scene(pane);
		
		// 3. add the scene to the stage (Window)
		stage.setScene(scene);

		// 4. set properties of the window
		stage.setTitle("Components Demo");

		// 5. show the window
		stage.show();
	}
	
	public static void main(String[] args) {
		Application.launch(args);
	}

Example Application Launcher – for UI defined in FXML

In this case, you create the “Scene” by loading the FXML file. Here’s an example for a scene defined in file GreeterUI.fxml.

public class MyApp extends Application {
    // Name of the FXML file containing scene.
    // Include the package as the path! (example: org.ske.greeter)
    String FXML_FILE = "org/ske/greeter/GreeterUI.fxml";

	/**
	 * @param stage the primary "stage" for showing the scene.
	 */
	@Override
	public void start(Stage stage) {
        // 1. Create a Scene from FXML
		Parent parent;
        try {
            parent = FXMLLoader.load(
                    this.getClass().getClassLoader().getResource(FXML_FILE) );
        } catch (IOException ex) {
            // Log the error and quit
            Logger.getLogger("MyApp").log(Level.SEVERE, null, ex);
            return;
        }
        Scene scene = new Scene(parent);

        // 2. Load the scene into stage (window)
        stage.setScene(scene);
        stage.setTitle("Greeter");
        // Resize the stage so the size matches the scene
        stage.sizeToScene();
        // 3. show the window
        stage.show();
	}

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

Be Careful of Imports!

JavaFX classes are in packages beginning with javafx., such as javafx.scene.control. Many JavaFX classes have the same name as a class in java.awt or javax.swing. If you import the wrong class, your application won’t work. If you are lucky, it won’t compile, too.

Package Meaning
javafx Top package for JavaFX framework
javafx.event JavaFX event classes
javafx.scene.control JavaFX controls, e.g. Button
javafx.scene.layout FlowPane, GridPane, other layouts
javafx.application The Application class

Beware of Imports from AWT and Swing Toolkits

You usually do not want classes from these packages, so if you see them imported into your JavaFX application, check to see if you are using the correct class or component.

For example, if your app has:

import java.awt.Button;
import java.awt.Label;

then you should use:

import javafx.scene.control.Button;
import javafx.scene.control.Label;
Package Meaning
java.awt Top package for AWT classes
java.awt.event AWT event classes
javax.swing Top package for Swing classes
javax.swing.event Swing event classes

Creating a UI with SceneBuilder

SceneBuilder is a stand-alone app, but it integrates with Java projects in Eclipse, Netbeans, and IntelliJ. You can use SceneBuilder to create a graphical interface for desktop and mobile applications.

Getting SceneBuilder

SceneBuilder

https://gluonhq.com/products/scene-builder - download SceneBuilder for your version of Java (Java 11 or Java 8).

  • The SceneBuilder 8.4.1 JAR download is 9.8MB, but contains only the Java program (as a JAR).
  • The Windows 64-bit installer is 51MB and the Debian/Ubuntu package is 57MB. They are big because they include the Java Runtime (JRE).

IDE Integration for SceneBuilder

To create a JavaFX user interface with your IDE, the only tool you need is SceneBuilder – you don’t need to install IDE plugins in Eclipse or Netbeans. The plugins provide extra functionality, but not required.

  • Eclipse: Select Window -> Preferences -> JavaFX and specify the location of the SceneBuilder JAR.
  • Netbeans: Select Tools -> Options -> Java (from top) -> JavaFX tab and choose the SceneBuilder directory. If you downloaded only the SceneBuilder JAR, Netbeans will complain that location is invalid. (So use a package.)
  • IntelliJ:

Eclipse Plugins (Two Choices)

  • E(fx)clipse is an Eclipse project. This plugin is huge, requiring many packages. Use a good Internet connection.
    • Install within Eclipse using Help->Install New Software. Select the Eclipse update site or use the E(fx)clipse update site for latest version.
  • Gluon Plugin for Oxygen, Neon, and Mars Eclipse releases. Gluon is the developer of SceneBuilder.
    • Install Gluon plugin within Eclipse using Help->Marketplace and search for Gluon.

Gluon.com IDE Plugins page describes the SceneBuilder integrations (extensions) for Eclipse, Netbeans, and IntelliJ.

  • Netbeans plugin is called “Gluon Plugin”. Install it using Netbeans: Tools -> Plugins, select “Available Plugins” tab and search for Gluon Plugin. This plugin also install Gradle and Groovy plugins. Gradle is a dependency management system and tends to download lots of libraries to a local cache.
  • IntelliJ install plugin from within IntelliJ. Use File -> Settings -> PLugins and search for “Gluon Plugin”. Gluon.com has step-by-step instructions.

How to Access a Controller class?

The FXMLLoader has access:

    FXMLLoader fxmlLoader = new FXMLLoader();
    Pane p = fxmlLoader.load(getClass().getResource("foo.fxml").openStream());
    FooController fooController = (FooController) fxmlLoader.getController();

another solution:

//Static global variable for the controller (where MyController is the name of your controller class static MyController myControllerHandle;

In the Main class for your application, change the static FXMLLoader.load to the instance version (as shown below). Then use the loader to access the controller.

@Override
public void start(Stage stage) throws Exception {
    //Set up instance instead of using static load() method
    FXMLLoader loader = new FXMLLoader(getClass().getResource("foo.fxml"));
    Parent root = loader.load();

    //Now we have access to getController() through the instance...
    myControllerHandle = (MyController)loader.getController();

    Scene scene = new Scene(root);

    stage.setScene(scene);
    stage.show();
}

How to Resize Container to Fit Components

In Swing, you can use pack() to resize a container to fit its components. You use this on the top-level container (e.g. JFrame):

class MyUI extends JFrame {
    
    private void initComponents() {
        JButton button = new JButton("Press me");
        JLabel label = new JLabel("Just do it");
        this.add(button);
        this.add(label);
        // resize everything to fit contents
        this.pack();
    }
}

To do this in JavaFX, call stage.sizeToScene(). But not clear if it will recursively resize contents the way Swing does.

References