Last updated: 9/10/2013
FXML is a scriptable, XML-based markup language for constructing Java object graphs. It provides a convenient alternative to constructing such graphs in procedural code, and is ideally suited to defining the user interface of a JavaFX application, since the hierarchical structure of an XML document closely parallels the structure of the JavaFX scene graph.
This document introduces the FXML markup language and explains how it can be used to simplify development of JavaFX applications.
In FXML, an XML element represents one of the following:
Class instances, instance properties, static properties, and define blocks are discussed in this section below. Scripting is discussed in a later section.
Class instances can be constructed in FXML in several ways. The most common is via instance declaration elements, which simply create a new instance of a class by name. Other ways of creating class instances include referencing existing values, copying existing values, and including external FXML files. Each is discussed in more detail below.
<?import javafx.scene.control.Label?>
This PI imports all classes from the javafx.scene.control package into the current namespace:
<?import javafx.scene.control.*?>
<?import javafx.scene.control.Label?> <Label text="Hello, World!"/>
Note that the Label’s "text" property in this example is set using an XML attribute. Properties can also be set using nested property elements. Property elements are discussed in more detail later in this section. Property attributes are discussed in a later section.
Classes that don't conform to Bean conventions can also be constructed in FXML, using an object called a "builder". Builders are discussed in more detail later.
Internally, the FXML loader uses an instance of com.sun.javafx.fxml.BeanAdapter to wrap an instantiated object and invoke its setter methods. This (currently) private class implements the java.util.Map interface and allows a caller to get and set Bean property values as key/value pairs.
<HashMap foo="123" bar="456"/>
<String fx:value="Hello, World!"/> <Double fx:value="1.0"/> <Boolean fx:value="false"/>
Custom classes that define a static valueOf(String) method can also be constructed this way.
<FXCollections fx:factory="observableArrayList"> <String fx:value="A"/> <String fx:value="B"/> <String fx:value="C"/> </FXCollections>
Builder support in FXML is provided by two interfaces. The javafx.util.Builder interface defines a single method named build() which is responsible for constructing the actual object:
public interface Builder<T> { public T build(); }
A javafx.util.BuilderFactory is responsible for producing builders that are capable of instantiating a given type:
public interface BuilderFactory { public Builder<?> getBuilder(Class<?> type); }
A default builder factory, JavaFXBuilderFactory, is provided in the javafx.fxml package. This factory is capable of creating and configuring most immutable JavaFX types. For example, the following markup uses the default builder to create an instance of the immutable javafx.scene.paint.Color class:
<Color red="1.0" green="0.0" blue="0.0"/>
Note that, unlike Bean types, which are constructed when the element's start tag is processed, objects constructed by a builder are not instantiated until the element's closing tag is reached. This is because all of the required arguments may not be available until the element has been fully processed. For example, the Color object in the preceding example could also be written as:
<Color> <red>1.0</red> <green>0.0</green> <blue>0.0</blue> </Color>
The Color instance cannot be fully constructed until all three of the color components are known.
When processing markup for an object that will be constructed by a builder, the Builder instances are treated like value objects - if a Builder implements the Map interface, the put() method is used to set the builder's attribute values. Otherwise, the builder is wrapped in a BeanAdapter and its properties are assumed to be exposed via standard Bean setters.
The <fx:include> tag creates an object from FXML markup defined in another file. It is used as follows:
<fx:include source="filename"/>
where filename is the name of the FXML file to include.
For example, given the following markup:
<?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <VBox xmlns:fx="http://javafx.com/fxml"> <children> <fx:include source="my_button.fxml"/> </children> </VBox>
If my_button.fxml contains the following:
<?import javafx.scene.control.*?> <Button text="My Button"/>
the resulting scene graph would contain a VBox as a root object with a single Button as a child node.
Note the use of the "fx" namespace prefix. This is a reserved prefix that defines a number of elements and attributes that are used for internal processing of an FXML source file. It is generally declared on the root element of a FXML document. Other features provided by the "fx" namespace are described in the following sections.
<fx:include> also supports attributes for specifying the name of the resource bundle that should be used to localize the included content, as well as the character set used to encode the source file. Resource resolution is discussed in a later section.
<fx:include source="filename" resources="resource_file" charset="utf-8"/>
<Button> <minHeight><Double fx:constant="NEGATIVE_INFINITY"/></minHeight> </Button>
For example, the following markup assigns a previously-defined Image instance named "myImage" to the "image" property of an ImageView control:
<ImageView> <image> <fx:reference source="myImage"/> </image> </ImageView>
Note that, since it is also possible to dereference a variable using the attribute variable resolution operator (discussed later in the Attributes section), fx:reference is generally only used when a reference value must be specified as an element, such as when adding the reference to a collection:
<ArrayList> <fx:reference source="element1"/> <fx:reference source="element2"/> <fx:reference source="element3"/> </ArrayList>
For most other cases, using an attribute is simpler and more concise.
At the moment, no JavaFX platform classes provide such a copy constructor, so this element is provided primarily for use by application developers. This may change in a future release.
Elements whose tag names begin with a lowercase letter represent object properties. A property element may represent one of the following:
For example, the following FXML creates an instance of the Label class and sets the value of the label's "text" property to "Hello, World!":
<?import javafx.scene.control.Label?> <Label> <text>Hello, World!</text> </Label>
This produces the same result as the earlier example which used an attribute to set the "text" property:
<?import javafx.scene.control.Label?> <Label text="Hello, World!"/>
Property elements are generally used when the property value is a complex type that can't be represented using a simple string-based attribute value, or when the character length of the value is so long that specifying it as an attribute would have a negative impact on readability.
The FXML loader uses the coerce() method of BeanAdapter to perform any required type conversions. This method is capable of performing basic primitive type conversions such as String to boolean or int to double, and will also convert String to Class or String to Enum. Additional conversions can be implemented by defining a static valueOf() method on the target type.
For example, the "children" property of javafx.scene.Group is a read-only list property representing the group's child nodes:
<?import javafx.scene.*?> <?import javafx.scene.shape.*?> <Group xmlns:fx="http://javafx.com/fxml"> <children> <Rectangle fx:id="rectangle" x="10" y="10" width="320" height="240" fill="#ff0000"/> ... </children> </Group>
As each sub-element of the <children> element is read, it is added to the list returned by Group#getChildren().
The "properties" property of javafx.scene.Node is an example of a read-only map property. The following markup sets the "foo" and "bar" properties of a Label instance to "123" and "456", respectively:
<?import javafx.scene.control.*?> <Button> <properties foo="123" bar="456"/> </Button>
For example, since javafx.scene.layout.Pane (the superclass of javafx.scene.layout.VBox) defines a default property of "children", a <children> element is not required; the loader will automatically add the sub-elements of the VBox to the container's "children" collection:
<?import javafx.scene.*?> <?import javafx.scene.shape.*?> <VBox xmlns:fx="http://javafx.com/fxml"> <Button text="Click Me!"/> ... </VBox>
Note that default properties are not limited to collections. If an element's default property refers to a scalar value, any sub-element of that element will be set as the value of the property.
For example, since javafx.scene.control.ScrollPane defines a default property of "content", a scroll pane containing a TextArea as its content can be specified as follows:
<ScrollPane> <TextArea text="Once upon a time..."/> </ScrollPane>
Taking advantage of default properties can significantly reduce the verbosity of FXML markup.
Static properties are prefixed with the name of class that defines them. For example, The following FXML invokes the static setter for GridPane's "rowIndex" and "columnIndex" properties:
<GridPane> <children> <Label text="My Label"> <GridPane.rowIndex>0</GridPane.rowIndex> <GridPane.columnIndex>0</GridPane.columnIndex> </Label> </children> </TabPane>
This translates roughly to the following in Java:
GridPane gridPane = new GridPane(); Label label = new Label(); label.setText("My Label"); GridPane.setRowIndex(label, 0); GridPane.setColumnIndex(label, 0); gridPane.getChildren().add(label);The calls to GridPane#setRowIndex() and GridPane#setColumnIndex() "attach" the index data to the Label instance. GridPane then uses these during layout to arrange its children appropriately. Other containers, including AnchorPane, BorderPane, and StackPane, define similar properties.
As with instance properties, static property elements are generally used when the property value cannot be efficiently represented by an attribute value. Otherwise, static property attributes (discussed in a later section) will generally produce more concise and readable markup.
For example, when working with radio buttons, it is common to define a ToggleGroup that will manage the buttons' selection state. This group is not part of the scene graph itself, so should not be added to the buttons' parent. A define block can be used to create the button group without interfering with the overall structure of the document:
<VBox> <fx:define> <ToggleGroup fx:id="myToggleGroup"/> </fx:define> <children> <RadioButton text="A" toggleGroup="$myToggleGroup"/> <RadioButton text="B" toggleGroup="$myToggleGroup"/> <RadioButton text="C" toggleGroup="$myToggleGroup"/> </children> </VBox>
Elements in define blocks are usually assigned an ID that can be used to refer to the element's value later. IDs are discussed in more detail in later sections.
An attribute in FXML may represent one of the following:
Each are discussed in more detail in the following sections.
<?import javafx.scene.control.*?> <Button text="Click Me!"/>
<Rectangle fx:id="rectangle" x="10" y="10" width="320" height="240" fill="#ff0000"/>
Unlike property elements, which are applied as they are processed, property attributes are not applied until the closing tag of their respective element is reached. This is done primarily to facilitate the case where an attribute value depends on some information that won't be available until after the element's content has been completely processed (for example, the selected index of a TabPane control, which can't be set until all of the tabs have been added).
Another key difference between property attributes and property elements in FXML is that attributes support a number of "resolution operators" that extend their functionality. The following operators are supported and are discussed in more detail below:
For example, the following markup creates an ImageView and populates it with image data from my_image.png, which is assumed to be located at a path relative to the current FXML file:
<ImageView> <image> <Image url="@my_image.png"/> </image> </ImageView>
Since Image is an immutable object, a builder is required to construct it. Alternatively, if Image were to define a valueOf(URL) factory method, the image view could be populated as follows:
<ImageView image="@my_image.png"/>
The value of the "image" attribute would be converted to a URL by the FXML loader, then coerced to an Image using the valueOf() method.
Note that whitespace values in the URL must be encoded; for example, to refer to a file named "My Image.png", the FXML document should contain the following:
<Image url="@My%20Image.png"/>
rather than:
<Image url="@My Image.png"/>
In FXML, resource substitution can be performed at load time for localization purposes. When provided with an instance of java.util.ResourceBundle, the FXML loader will replace instances of resource names with their locale-specific values. Resource names are identified by a "%" prefix, as shown below:
<Label text="%myText"/>
If the loader is given a resource bundle defined as follows:
myText = This is the text!
the output of the FXML loader would be a Label instance containing the text "This is the text!".
<fx:define> <ToggleGroup fx:id="myToggleGroup"/> </fx:define> ... <RadioButton text="A" toggleGroup="$myToggleGroup"/> <RadioButton text="B" toggleGroup="$myToggleGroup"/> <RadioButton text="C" toggleGroup="$myToggleGroup"/>
<Label text="\$10.00"/>
Attribute variables as shown above are resolved once at load time. Later updates to the variables value are not automatically reflected in any properties to which the value was assigned. In many cases, this is sufficient; however, it is often convenient to "bind" a property value to a variable or expression such that changes to the variable are automatically propagated to the target property. Expression bindings can be used for this purpose.
<TextField fx:id="textField"/> <Label text="${textField.text}"/>
As the user types in the text input, the label's text content will be automatically updated.
More complex expression are also supported. A list of supported constants and operators follows:
"string" 'string' | A string constant |
true false | A boolean constant |
null | A constant representing the null value |
50.0 3e5 42 | A numerical constant |
- (unary operator) | Unary minus operator, applied on a number |
! (unary operator) | Unary negation of a boolean |
+ - * / % | Numerical binary operators |
&& || | Boolean binary operators |
> >= < <= == != |
Binary operators of comparison. Both arguments must be of type Comparable |
<GridPane> <children> <Label text="My Label" GridPane.rowIndex="0" GridPane.columnIndex="0"/> </children> </TabPane>
Event handler attributes are a convenient means of attaching behaviors to document elements. Any class that defines a setOnEvent() method can be assigned an event handler in markup.
FXML supports three types of event handler attributes: script event handlers, controller method event handlers and expressions. Each are discussed below.
<?language javascript?> ... <VBox> <children> <Button text="Click Me!" onAction="java.lang.System.out.println('You clicked me!');"/> </children> </VBox>
A controller method event handler is a method defined by a document's "controller". A controller is an object that is associated with the deserialized contents of an FXML document and is responsible for coordinating the behaviors of the objects (often user interface elements) defined by the document.
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml"> <children> <Button text="Click Me!" onAction="#handleButtonAction"/> </children> </VBox>
package com.foo; public class MyController { public void handleButtonAction(ActionEvent event) { System.out.println("You clicked me!"); } }
the handleButtonAction() will be called when the user presses the button, and the text "You clicked me!" will be written to the console.
package com.foo; public class MyController { public void handleButtonAction() { System.out.println("You clicked me!"); } }
Controllers are discussed in more detail in a later section.
Any expression that point to a variable of javafx.event.EventHandler type can be used as an expression handler.
Previous example using an expression handler:
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml"> <children> <Button text="Click Me!" onAction="$controller.onActionHandler"/> </children> </VBox>
With the controller that contains a field like this
public class MyController { @FXML public EventHandleronActionHandler = new EventHandler<>() { ... } ... }
Note that other kinds of expressions, like binding expressions are not supported in this context.
Collections and object properties cannot be listen to using setOnEvent() methods. For these reason, special handler methods need to be used. ObservableList, ObservableMap or ObservableSet uses a special onChange attribute that points to a handler method with a ListChangeListner.Change, MapChangeListener.Change or SetChangeListener.Change parameter respectively.
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml"> <children onChange="#handleChildrenChange"/> </VBox>where the handler method looks like this:
package com.foo; import javafx.collections.ListChangeListener.Change; public class MyController { public void handleChildrenChange(ListChangeListener.Change c) { System.out.println("Children changed!"); } }
Similarly, the property handlers are methods that have the same parameters as changed method of ChangeListener :
changed(ObservableValue<? extends T> observable, T oldValue, T newValue)
A handler for parent property would look like this
public class MyController { public void handleParentChange(ObservableValue value, Parent oldValue, Parent newValue) { System.out.println("Parent changed!"); } }
For convenience, the first parameter can be a subclass of ObservableValue, e.g. Property
For registering to a property, a special on<propertyName>Change attribute must be used.
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml" onParentChange="#handleParentChange"/>
Note that collections and properties do not currently support scripting handlers.
For example, the following markup defines a function called handleButtonAction() that is called by the action handler attached to the Button element:
<?language javascript?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <VBox xmlns:fx="http://javafx.com/fxml"> <fx:script> function handleButtonAction(event) { java.lang.System.out.println('You clicked me!'); } </fx:script> <children> <Button text="Click Me!" onAction="handleButtonAction(event);"/> </children> </VBox>
Clicking the button triggers the event handler, which invokes the function, producing output identical to the previous examples.
<?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <VBox xmlns:fx="http://javafx.com/fxml"> <fx:script source="example.js" charset="cp1252"/> <children> <Button text="Click Me!" onAction="handleButtonAction(event);"/> </children> </VBox>
function handleButtonAction(event) { java.lang.System.out.println('You clicked me!'); }
It is often preferable to separate code from markup in this way, since many text editors support syntax highlighting for the various scripting languages supported by the JVM. It can also help improve readability of the source code and markup.
Note that script blocks are not limited to defining event handler functions. Script code is executed as it is processed, so it can also be used to dynamically configure the structure of the resulting output. As a simple example, the following FXML includes a script block that defines a variable named "labelText". The value of this variable is used to populate the text property of a Label instance:
<fx:script> var myText = "This is the text of my label."; </fx:script> ... <Label text="$myText"/>
Warning:As of JavaFX 8.0, importClass() javascript function is no longer supported. You have to use fully qualified names as in the example above or load a nashorn compatibility script.
load("nashorn:mozilla_compat.js"); importClass(java.lang.System); function handleButtonAction(event) { System.out.println('You clicked me!'); }
While it can be convenient to write simple event handlers in script, either inline or defined in external files, it is often preferable to define more complex application logic in a compiled, strongly-typed language such as Java. As discussed earlier, the fx:controller attribute allows a caller to associate a "controller" class with an FXML document. A controller is a compiled class that implements the "code behind" the object hierarchy defined by the document.
As shown earlier, controllers are often used to implement event handlers for user interface elements defined in markup:
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml"> <children> <Button text="Click Me!" onAction="#handleButtonAction"/> </children> </VBox>
package com.foo; public class MyController { public void handleButtonAction(ActionEvent event) { System.out.println("You clicked me!"); } }
public void initialize();
For example, the following code defines an initialize() method that attaches an action handler to a button in code rather than via an event handler attribute, as was done in the previous example. The button instance variable is injected by the loader as the document is read. The resulting application behavior is identical:
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml"> <children> <Button fx:id="button" text="Click Me!"/> </children> </VBox>
package com.foo; public class MyController implements Initializable { public Button button; @Override public void initialize(URL location, Resources resources) button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { System.out.println("You clicked me!"); } }); } }
For example, the controllers from the previous examples could be rewritten as follows:
package com.foo; public class MyController { @FXML private void handleButtonAction(ActionEvent event) { System.out.println("You clicked me!"); } }
package com.foo; public class MyController implements Initializable { @FXML private Button button; @FXML protected void initialize() button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { System.out.println("You clicked me!"); } }); } }
In the first version, the handleButtonAction() is tagged with @FXML to allow markup defined in the controller's document to invoke it. In the second example, the button field is annotated to allow the loader to set its value. The initialize() method is similarly annotated.
<VBox fx:controller="com.foo.MainController"> <fx:define> <fx:include fx:id="dialog" source="dialog.fxml"/> </fx:define> ... </VBox>
public class MainController extends Controller { @FXML private Window dialog; @FXML private DialogController dialogController; ... }
when the controller's initialize() method is called, the dialog field will contain the root element loaded from the "dialog.fxml" include, and the dialogController field will contain the include's controller. The main controller can then invoke methods on the included controller, to populate and show the dialog, for example. Note that as the content of the file referenced by fx:include otherwise would become part of the scene graph spanned from main_window_content.fxml, it is necessary to wrap fx:include by fx:define to separate the scene graphs of both windows.
The FXMLLoader class is responsible for actually loading an FXML source file and returning the resulting object graph. For example, the following code loads an FXML file from a location on the classpath relative to the loading class and localizes it with a resource bundle named "com.foo.example". The type of the root element is assumed to be a subclass of javafx.scene.layout.Pane, and the document is assumed to define a controller of type MyController:
URL location = getClass().getResource("example.fxml"); ResourceBundle resources = ResourceBundle.getBundle("com.foo.example"); FXMLLoader fxmlLoader = new FXMLLoader(location, resources); Pane root = (Pane)fxmlLoader.load(); MyController controller = (MyController)fxmlLoader.getController();
The
For example, the following markup defines the structure of a simple custom control containing a TextField and a Button instance. The root container is defined as an instance of javafx.scene.layout.VBox:
<?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <fx:root type="javafx.scene.layout.VBox" xmlns:fx="http://javafx.com/fxml"> <TextField fx:id="textField"/> <Button text="Click Me" onAction="#doSomething"/> </fx:root>
As mentioned earlier, the <fx:root> tag creates a reference to a previously defined root element. The value of this element is obtained by calling the getRoot() method of FXMLLoader.
In the following example, the CustomControl class extends VBox (the type declared by the <fx:root> element), and sets itself as both the root and controller of the FXML document in its constructor. When the document is loaded, the contents of CustomControl will be populated with the contents of the previous FXML document:
package fxml; import java.io.IOException; import javafx.beans.property.StringProperty; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.control.TextField; import javafx.scene.layout.VBox; public class CustomControl extends VBox { @FXML private TextField textField; public CustomControl() { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("custom_control.fxml")); fxmlLoader.setRoot(this); fxmlLoader.setController(this); try { fxmlLoader.load(); } catch (IOException exception) { throw new RuntimeException(exception); } } public String getText() { return textProperty().get(); } public void setText(String value) { textProperty().set(value); } public StringProperty textProperty() { return textField.textProperty(); } @FXML protected void doSomething() { System.out.println("The button was clicked!"); } }
Now, callers can use instances of this control in code or in markup, just like any other control; e.g.:
HBox hbox = new HBox(); CustomControl customControl = new CustomControl(); customControl.setText("Hello World!"); hbox.getChildren().add(customControl);
<HBox> <CustomControl text="Hello World!"/> </HBox>
Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.