By Barry Burd

Using the JavaFX framework, developers add useful, visually appealing components to their Java applications. JavaFX is one of several such frameworks, beginning with the Abstract Windowing Toolkit in 1995 and Java Swing in 1998. The first version of JavaFX dates back to 2008, but JavaFX became a first-class citizen in the standard Java library with the second update of Java 7 in 2011.

Also in 2011, Oracle released Version 2 of JavaFX. This new version combined XML documents with Java code — declaring the look of an app with XML and the actions of an app with Java code. JavaFX uses its own dialect of the XML language, called FXML.

(If you care about the origins of acronyms, XML stands for the eXtended Markup Language, and JavaFX probably has something to with Java “special EFF-ECTS”. So, depending on your taste, FXML stands for either EFF-ects eXtended Markup Language or EFF-ECTS Markup Language. Take your pick.)

This article describes some of the names that you find in a simple JavaFX program. (Bear in mind that this reference to “some of the names” means “the names that belong exclusively to the world of JavaFX” — this doesn’t include names like TextField and Button that appear in other windowing environments, and it doesn’t include names like java.lang and main, which belong to vanilla Java technologies.)

Listing 1 contains FXML code, and Listing 2 contains Java code. When you run these two listings as part of a single app, you get a program that capitalizes the letters in your text. (At this point, you might sarcastically say “An app that capitalizes text? Big deal!” An appropriate response here would be “AN APP THAT CAPITALIZES TEXT? BIG DEAL!”)

Listing 1: The Root.fxml File

<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefHeight="130.0" prefWidth="198.0"
  xmlns="http://javafx.com/javafx/8" 
  xmlns:fx="http://javafx.com/fxml/1"
  fx:controller="application.Main">
  <children>
    <TextField fx:id="textField" 
               layoutX="25.0" layoutY="26.0" />
    <Button layoutX="73.1875" layoutY="65.0" 
            mnemonicParsing="false"
            onAction="#onClick" 
            text="Capitalize" />
  </children>
</AnchorPane>

Listing 2: The Main.java File

package application;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class Main extends Application {
  public static void main(String[] args) {
    launch(args);
  }
  @Override
  public void start(Stage primaryStage) {
    try {
      Parent root = FXMLLoader.load(getClass()
          .getResource("Root.fxml"));
      Scene scene = new Scene(root, 400, 400);
      scene.getStylesheets().add(
          getClass().getResource("application.css")
              .toExternalForm());
      primaryStage.setScene(scene);
      primaryStage.show();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  @FXML
  private TextField textField;
  @FXML
  protected void onClick(ActionEvent event) {
    textField.setText(textField.getText().toUpperCase());
  }
}

The FXML code

Like every XML document, the document in Listing 1 has a root element — a single element that starts at the beginning of the document and ends at the very end of the document. In Listing 1, the root element starts with

<AnchorPane ...

and ends with

</AnchorPane>

The lines beginning with <? (at the top of Listing 1) don’t count as XML elements.

The AnchorPane as a root element

An AnchorPane (or more formally, a javafx.scene.layout.AnchorPane) is a place where things can be anchored. Think about trying to put a button or a text field on a big, empty space. Without an AnchorPane, these components float willy-nilly inside the space. With an AnchorPane, you can make the text field’s left edge be exactly 25.0 pixels from the left edge of the AnchorPane. (See the TextField element’s layoutX attribute in Listing 1.) Also, with an AnchorPane, you can make the text field’s top edge be exactly 26.0 pixels from the top edge of the AnchorPane. (See the TextField element’s layoutY attribute in Listing 1.) The same holds true for a button or for any other component that you plant inside the AnchorPane.

Inside an FXML document’s root element, an fx:controller attribute tells Java the name of the controller class — the class whose code performs actions associated with the app. In Listing 1, the controller class’s name is application.Main. And what a coincidence! The class in Listing 2 is named Main, and it’s in a package named application!

If you think of the FXML code as an outline, it has a heading with subheadings, and with subheadings within subheadings, and so on. In Listing 1, primary heading is AnchorPane. The only subheading of AnchorPane is children. But children has two subheadings of its own; namely, TextField and Button.

The fx:id attribute

The TextField element has an fx:id attribute. This attribute tells you how to find this component inside some Java code. In other words,

<TextField fx:id="textField"

says “To refer to this widget inside the application.Main Java code, use the name textField.” (If you want more specifics, peek ahead to the discussion of the code in Listing 2.)

You don’t have to use a descriptive word to identify a component. You can write

<TextField fx:id="woofinflang"

As long as you use the word woofinflang consistently (by referring to the word woofinflang in your Java code) everything will go smoothly. Of course names like textField, textField2 and phoneNumberField are more informative than names like woofinflang. So stay away from woofinflangs if you possibly can.

The mnemonicParsing attribute

In Listing 1, inside the Button element, the mnemonicParsing attribute has the value false. This false value tells Java not to bother setting a shortcut key for the button. If the value were true, you could add an underscore to the value of the button’s text attribute:

text="_Capitalize"

Then the user wouldn’t have to move the mouse over the button. Because the underscore comes immediately before the letter C, pressing Alt+C would have the same effect as clicking the button.

The onAction attribute

A button’s onAction attribute tells Java the name of the method to execute when the user clicks the button. In Listing 1, the onAction attribute’s value is #onClick. This tells Java to call the controller class’s onClick method when the user clicks the button. Fortunately, the application.Main class in Listing 2 has an onClick method.

In Listing 1, the onAction value is #onClick. But in Listing 2, the corresponding method name is onClick without the hash symbol. In a button’s onAction attribute, the hash symbol (#) isn’t part of the method name. But that doesn’t mean you can omit the hash symbol in your FXML document. If you omit the hash symbol then, when you try to run the program, you’ll see an ugly error message.

The Java code

The class in Listing 2 extends the Application class. An Application is exactly what you think it is — a bunch of code that a user can launch; a program with a clearly-stated purpose such as “Create a document,” “Surf the Web” or “Find a mate.”

Running and launching

There are at least two ways to run a JavaFX program. One way is to run it as an ordinary Java application. For example, in Eclipse, you select Run As->Java Application.

When you do this, your computer starts the Java virtual machine, which in turn calls the program’s main method. In Listing 2, the main method executes only one statement — a call to the launch method. Calling the launch method sets the app’s JavaFX wheels run in motion.

Alternatively, you can run prepackaged JavaFX code. A prepackaged bundle includes everything a computer needs in order to run an application. This “everything” includes code to check for a Java virtual machine on the user’s computer, and code to download a Java virtual machine if the computer doesn’t already have one. When you prepackage a JavaFX application this way, your program doesn’t need a main method. The system calls the program’s launch method automatically.

A .jar file is like a .zip file, except that every .jar file contains certain elements specific to Java programs. One of the things you can put in a .jar file is a prepackaged JavaFX application.

When you call the launch method, Java responds by making calls to your application’s init and start methods. You don’t see an init method in Listing 2 because your Main class inherits the Application class’s default init method. (That’s okay because the default init method doesn’t do anything.)

Things inside of other things

The start method in Listing 2 creates a Parent. The Parent is the starting point of a Scene, and the Scene appears on a Stage. Here’s a bit more detail:

  • A Stage is what you’d normally call a “window.”

    It’s a rectangular work area on the user’s screen.

  • A Scene (also known as a scene graph) is a tree of components.

    For example, a Scene might contain two panes. The leftmost pane contains two smaller panes — a top pane and a bottom pane. The top pane contains a button; the bottom pane contains a text field. The rightmost pane might contain an image and a label for the image.

    In this article’s application, the tree of components is pretty simple. The Scene contains an AnchorPane which in turn contains a TextField and a Button. (See Listing 1.)

  • A Parent is the starting point for a Scene.

    Despite what appears in the previous bullet, a Scene can’t begin its life by having two panes, or by having two of anything. Every Scene starts with a single component, and that component must be of type Parent. So in this article’s application, the Scene contains a Parent, which contains an AnchorPane, which contains a TextField and a Button.

The start method in Listing 2 connects a Parent to the components described in Listing 1, associates a Scene with the Parent, and then associates a Stage with the Scene. Finally, the code displays the Stage with a call to the Stage class’s show method.

If you’re familiar with web page design, you can use cascading style sheets (CSS) to describe the look of a scene. In Listing 2, the call to scene.getStyleSheets().add associates a style sheet with your scene. If your .css file is blank (as it is in this article’s example), then calling scene.getStyleSheets().add has no effect.

Taking action

In Listing 1, the line

<TextField fx:id="textField"

gives you a way to refer to one of the components on the user’s screen. So in Listing 2, the line

private TextField textField;

makes this textField component be an object in your Java code.

Again in Listing 1, the button’s onAction attribute tells Java to call the controller class’s onClick method when the user clicks the button. So in Listing 2, the onClick method fiddles with the text inside the textField component. (More specifically, the onClick method gets the text in the textField, capitalizes the text, and then puts the capitalized text back into the textField.) This is how the program knows what to do when the user clicks the button.

You don’t always have to use words like textField. You can name something bershmlug as long as you use the name consistently. In the FXML file, you write

<TextField fx:id="bershmlug"

and in the Java code, you write

@FXML
private TextField bershmlug;
@FXML
protected void onClick(ActionEvent event) {
  bershmlug.setText(bershmlug.getText().toUpperCase());
}

The @FXML annotations in Listing 2 are for access control. When you run a JavaFX program, a loader grabs your FXML code and converts it into Java code. (It “loads” the FXML code into your program.) In order to do its job, the loader must access names like textField and onClick in Listing 2. But remember: This loader isn’t part of your own program. The loader belongs to Java’s standard libraries.

How can you control access to the names textField and onClick? Java’s ordinary access modifiers (public, protected, private and default) leave you little choice. With these modifiers, the only way to permit access by an outside program is to declare textField and onClick to be public. But, for many developers, the indiscriminate use of public access is considered gauche. With public access, every class has access to textField and onClick. That’s not really what a JavaFX developer wants.

To solve this problem, the @FXML annotation provides a special kind of access. In Listing 2, the textField variable is private so, ordinarily, no class other than Main can access the textField variable. But the @FXML annotation grants special privilege to the loader. Unlike any other code, the loader code can reference the textField variable. When you compile and run your program, Java sees the @FXML annotation and does special tricks to provide access to the loader.

The same kind of thing is true for the onClick method. Without the @FXML annotation, the protected onClick method could be called only from classes in your own application package, and from subclasses of your Main class. The loader is neither of these things. So to grant special access by the loader to your onClick method, you preface your onClick method declaration with @FXML.