javafx FXML and Controllers Example FXML


A Simple FXML document outlining an AnchorPane containing a button and a label node:

<?xml version="1.0" encoding="UTF-8"?>

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

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="" 
        <Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
        <Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />

This example FXML file is associated with a controller class. The association between the FXML and the controller class, in this case, is made by specifying the class name as the value of the fx:controller attribute in the root element of the FXML: fx:controller="com.example.FXMLDocumentController". The controller class allows for Java code to be executed in response to user actions on the UI elements defined in the FXML file:

package com.example ;

import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;

public class FXMLDocumentController {
    private Label label;
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");
    public void initialize(URL url, ResourceBundle resources) {
        // Initialization code can go here. 
        // The parameters url and resources can be omitted if they are not needed

An FXMLLoader can be used to load the FXML file:

public class MyApp extends Application {

    public void start(Stage stage) throws Exception {

        FXMLLoader loader = new FXMLLoader();
        Parent root = loader.load();
        Scene scene = new Scene(root);


The load method performs several actions, and it is useful to understand the order in which they happen. In this simple example:

  1. The FXMLLoader reads and parses the FXML file. It creates objects corresponding to the elements defined in the file, and makes note of any fx:id attributes defined on them.

  2. Since the root element of the FXML file defined a fx:controller attribute, the FXMLLoader creates a new instance of the class that it specifies. By default this happens by invoking the no-argument constructor on the class specified.

  3. Any elements with fx:id attributes defined which have fields in the controller with matching field names, and which are either public (not recommended) or annotated @FXML (recommended) are "injected" into those corresponding fields. So in this example, since there is a Label in the FXML file with fx:id="label" and a field in the controller defined as

    private Label label ;

    the label field is initialized with the Label instance created by the FXMLLoader.

  4. Event handlers are registered with any elements in the FXML file with onXXX="#..." properties defined. These event handlers invoke the specified method in the controller class. In this example, since the Button has onAction="#handleButtonAction", and the controller defines a method

    private void handleButtonAction(ActionEvent event) { ... }

    when an action is fired on the button (e.g. the user presses it), this method is invoked. The method must have void return type, and can either define a parameter matching the event type (ActionEvent in this example), or can define no parameters.

  5. Finally, if the controller class defines an initialize method, this method is invoked. Notice this happens after the @FXML fields have been injected, so they can be safely accessed in this method and will be initialized with the instances corresponding to the elements in the FXML file. The initialize() method can either take no parameters, or can take a URL and a ResourceBundle. In the latter case, these parameters will be populated by the URL representing the location of the FXML file, and any ResourceBundle set on the FXMLLoader via loader.setResources(...). Either of these can be null if they were not set.