JavaFX FXML GUI Design
JavaFX can use a simple language named FXML, making it easy to design GUIs with XML. This section explains the basic use of FXML.
What Is FXML?
JavaFX is a GUI library created with an emphasis on quickly developing applications with rich GUIs. However, from what we have seen so far, you may have felt that it is not very different from Swing. Setting action events was simple, but many people may have thought that if that is all it offers, there is no need to migrate from Swing.
In fact, JavaFX does not put the main emphasis on creating Java classes and building GUIs directly in Java source code. What is even more important is GUI design using FXML.
FXML is an XML-based GUI markup language included with JavaFX. Although it is called a language, it is XML-based markup, so it is much easier to write than Java source code. You can design a GUI simply by describing containers and controls in XML. After that, you only need a small amount of Java code to load and display it, and you can create a full GUI application.
About JavaFX Scene Builder
The advantage of FXML being XML-based is not only that it is easy to write. Because it is XML-based, it is easy to analyze, and various tools can make design easier. Oracle, the Java vendor, provides an FXML-based GUI design tool named JavaFX Scene Builder.
This tool lets you create FXML source code simply by dragging and placing parts with the mouse. Using GUI design tools is practically essential when working with FXML. First, make sure you can use such a tool.
JavaFX Scene Builder download location:
http://www.oracle.com/technetwork/java/javase/downloads/javafxscenebuilder-info-2157684.html
Basic FXML Code
What does an FXML file look like? Let’s roughly understand its basic code.
FXML is written as a text file with the .fxml extension. The basic form of this source code is roughly as follows.
Basic form of FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import XX ?>
<PaneClass
xmlns="..."
xmlns:fx="...">
<!-- controls integrated into the Pane -->
</PaneClass>
After <?xml ?>, provide an <?import ?> tag corresponding to Java’s import statement. This imports the classes you use. If you do not write <?import ?> tags, you must write classes with their full package names, so be careful.
The root tag, or top-level tag, of FXML is written with a Pane class tag. For example, for BorderPane, write a <BorderPane> tag and then write control tags inside it.
In general, FXML recognizes Java class names when they are written directly as tag names. For Label, use <Label>.
The root tag includes the xmlns XML namespace attribute. It also includes xmlns:fx, the namespace attribute for FXML itself. These two attributes let the XML code be recognized as FXML.
Actually, if you are simply loading and using an FXML file from Java code, these namespace attributes are not required. Even without them, Java can load and use the FXML properly.
They are useful when using GUI authoring tools, but they are not strictly required. Even so, make it a habit to write them as the basic form of FXML.
The following is a basic FXML example.
<?import XX ?>
<PaneClass
xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1">
<!-- controls integrated into the Pane -->
</PaneClass>
Using FXML
Let’s create a simple sample that uses FXML. The following code is an FXML example.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<BorderPane
xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1">
<top>
<Label text="This is FXML!" />
</top>
</BorderPane>
This simply adds one Label to a BorderPane. The contents are explained below.
<? import?> Tag
Several <? import?> statements are written at the beginning. These are actually added automatically when created with JavaFX Scene Builder. They prepare import statements for Pane and control-related classes.
<BorderPane> Tag
Here, a <BorderPane> tag is written, and a <Label> tag is placed inside it. Looking closely, the Label is not written directly inside BorderPane; it is surrounded by a <Top> tag. This is specific to BorderPane, where you write controls inside tags that represent the location where they are attached. The following five are available.
Position Tags of <BorderPane>
<Top>, <Bottom>, <Right>, <Left>, <Ceter>
<Label> Tag
In the <Label> tag, the text to display is specified with the text attribute. Control properties can be written as attributes in this way. It is easy to understand if you think of text="OO" as doing the same kind of work as setText("OO").
In this way, many setOO(value) operations that set properties on controls can be rewritten as OO=value attributes on control tags. This applies not only to Label, but to controls in general.
Loading FXML
FXML naturally does not work just by being written. It becomes usable only when it is loaded and instantiated on the Java class side and then included in a window. Usually this processing is written in the start method of the Application class. Let’s summarize the flow of using FXML.
Loading a Pane
Load FXML and create a Pane instance. Use the FXMLLoader class in the javafx.fxml package. By calling its load class method, you can load the FXML file and get an instance.
FXMLLoader.load(URL)
Pass a URL instance as the argument. If the FXML file is stored in the same location as the Application class, it is best to load it with the getResource method of Class. In other words, use the following form.
variable = FXMLLoader.load(getClass().getResource("xxx.fxml"));
Specify the FXML file name to load in xxx.fxml. Be careful about the returned instance. It is cast to an Object instance, so after retrieving it, convert it to the original Pane instance before use.
Add to Scene
Once you have obtained the Pane instance from FXML, the rest is simple. When creating the Scene instance, specify this Pane as an argument, prepare the Scene, and set it on the Stage.
Scene variable = new Scene(PaneInstance, width, height);
Scene can be created like this. Even when using FXML, once you have a Pane instance, the rest is no different.
The following is an actual usage example.
package com.devkuma.javafx;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class App extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
BorderPane root;
try {
root = (BorderPane)FXMLLoader.load(getClass().getResource("app.fxml"));
Scene scene = new Scene(root,200,100);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
This code assumes that a file named app.fxml is placed in the same location as the com.devkuma.javafx.App class. Actually place the previous FXML file there and try running it. The window should appear correctly.
Using Style Sheets
There is a clearer way to configure detailed display settings for controls than writing them directly as FXML attributes. It is to use style sheets. JavaFX has a feature that reads and applies control properties from style sheets. With it, you can configure control appearance easily without writing Java code.
Using a style sheet is simple. Write a style sheet in the FXML Pane tag as follows.
<stylesheets>
<URL value="@style sheet"/>
</stylesheets>
Inside the <stylesheets> tag, provide the URL of the style sheet to load. You can write as many as needed. In the <URL> tag, specify the path to the style sheet with value. By writing it as @file name, you can specify a style sheet file in the same location as the FXML file.
The following source code adds a style sheet to the previous FXML.
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.URL ?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<BorderPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<stylesheets>
<URL value="@app.css" />
</stylesheets>
<top>
<Label fx:id="label1" text="This is FXML!" />
</top>
</BorderPane>
This loads app.css from the same location as the FXML file. Here, an ID is assigned to the <Label> tag so the style sheet can be applied.
<Label fx:id="label1"... />
By writing fx:id this way, you can assign an ID to the control. In a style sheet, this ID can be used to apply styles to a specific control.
Writing a Style Sheet
Now let’s write a style sheet. First, create a file named app.css in the same location as the FXML file.
Then write styles for the <Label fx:id="label1"/> control in that file. The following is a simple example.
@CHARSET "utf-8";
Label#label1 {
-fx-font-family:Serif;
-fx-font-size:24pt;
}
Character Encoding
At the beginning, @CHARSET "utf-8"; is written. Basically, style sheets are encoded in UTF-8. This is not mandatory, but consider it the standard way to write them.
Control Style
Here, a style is written for the Label with the ID label1.
Label#label1 {...}
Styles are specified in the form class name#ID name. It feels similar to writing tag name#ID in HTML styles.
Of course, if you specify only the class name, you can apply the style to all controls of that class. For example, Label {...} sets styles for all Label controls together.
Font Properties
Two styles are written here: -fx-font-family and -fx-font-size. These specify the font family name and font size.
JavaFX style names all begin with -fx- like this. Many HTML style names can be used by adding -fx- to the front, but not all of them work that way.
For example, background color is -fx-background-color, but text color is -fx-text-fill. JavaFX has its own values as well, so be careful.