JavaFX, or how I worked with insufficient documentation for UI design

5 minute read

My current CS class is going through concepts in Java and the past week has been about JavaFX and event-driven programming. Now there isn’t much to talk about in terms of JavaFX but I thought I should write down what I thought about it anyways, since it’s somewhat similar to writing apps in JavaScript and Vue.js. I had to work on an assignment with JavaFX so some details about that I’ll also include.

I did try out Java Swing a while back (like a long while back) but now it seems to be discontinued and been replaced by JavaFX.
Then again, JavaFX is also now not included in the Java SDK packages so…

That leads me to the first issue I had with working on that assignment. The JavaFX SDK we had to use was by Gluon for Java 11. There wasn’t official online documentation, only Javadoc files to download. Fortunately, it seems the libraries stayed pretty much similar so I could still reference the Java 8 Oracle documentation.

Components

The JavaFX library is pretty extensive but the main libraries I used was javafx.event for event handling and javafx.scene and javafx.stage for the nodes and panes.
Since the library is massive, it would be slow to do import javafx.* even though I wanted to super badly. Instead, I imported each component in one by one, which lead to a massive import forehead in the file.

In JavaFX, the application class has to extend Application and contain the start() method, which sets up all the components to your application. The application window is called a Stage and a Scene containing Panes are added to the Stage.

1
2
3
4
5
6
7
8
public class myApplication extends Application {
    public void start(Stage stage) {
        Pane pane = new Pane();         // this is where you can add nodes
        stage.getChildren().add(new Scene(pane, 400, 300));
        // a window is created with a width of 400 and height of 300
        stage.show();
    }
}

Each pane can be accessed in the javafx.scene.layout library and they provide different customizable layouts that you can then put other elements (called Nodes in JavaFX) into. For my assignment, I used a BorderPane which looks like this:

Nodes can also be arranged nicely in child panes that are then placed in the main one. Here, I used VBox (arranges items in rows down) and HBox (arranges items in columns across) to arrange them. Generally, items are added via the getChildren().add() or getChildren.addAll() methods. The largest departure I found in JavaFX from JavaScript applications is that there isn’t the HTML DOM system of id-ing elements, so the only ways to get method access to another element in some other pane or container, I had to make it a global object or access it through a chain of getChildren().get()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// I wanted to change text in a VBox from outside the VBox, so I had to do this
private final Button deleteButton = new Button();
private final Button editButton = new Button();

public void start(Stage stage) {
    // I had also implemented the dynamic creation of the VBox in a separate method, which added to the complexity
    VBox container = createBottomBox();

    // code here to add the nodes into the scene and whatnot
}

public VBox createBottomBox() {
    VBox vbox = new VBox();
    Text text = new Text("Hello world!");
    deleteButton.setOnAction(e -> {
        vbox.getChildren().remove(0);       // uses indexing, which with lots of elements inside gets pretty wacky
    });
    // this was even worse, I think
    editButton.setOnAction(e -> {
        ((Text) vbox.getChildren().get(0)).setText("Hello, not world");
    });
}

Although I will admit, it may have been in part due to my poor planning of the application in the first place. I’m also not entirely sure if there is a better alternative.

Nodes

Nodes can, for me, be categorized into two types: controls and the other stuff. Controls are items that the user can interact with, like buttons and text fields, while the other stuff is where information is presented to the user, like text or pictures and shapes.

Since they can be interacted with, controls have a setOnAction() method, which acts similarly to the addEventListener() method in JavaScript (there’s a more direct alternative for JavaFX as well). This method will fire an Event, which will be handled by the handle() method of the EventHandler class.

1
2
3
4
5
6
7
8
9
10
11
12
13
Button b = new Button();
b.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent e) {
        System.out.println("Hello there");
    }
});

// there is also a shorthand alternative, the lambda expression
// here, e is the Event object sent to the handler
b.setOnAction(e -> {
    System.out.println("Hello there");
})

Some controls I frequently used were:

  • Button - your typical button
  • Menu, MenuItem and MenuBar - creates the bar, usually along the top of an application window, with options like “File” and “Edit”
  • ContextMenu - shows a menu when you interact with the object
  • TextField and TextArea - places where the user can enter text
  • ScrollPane - provides an area to add items and scroll through in

and some non-control items I used were:

  • Text - it’s just text
  • Font - allows you to set a font and size to a text
  • Color - also just color
  • javafx.scene.shape.* - the different shapes that can be created, like Rectangles and Circles

Now, the non-control items couldn’t normally be interacted with but with MouseEvent it can be done

1
2
3
4
VBox box = new VBox();
box.setOnMouseClicked(e -> {
    System.out.println("Clicked a box!");
});

Styling

Styles in JavaFX can be controlled through CSS styles and even stylesheets, typically with the prefix -fx- and separated with a semicolon “;”. Using the setStyle() method for each elements works:

1
text.setStyle("-fx-background-color: red; -fx-font: 16 Arial");

or setting individual parts using their own method (which is quite hard to find if you don’t know what you’re looking for):

1
text.setFill(Color.RED);

Doing it through stylesheets may be the easiest way though, especially if you have experience with HTML and CSS styling already:

/* CSS file: stylesheet.css */
.button1 {
    -fx-base: red;
    -fx-font: 20 Times;
    -fx-padding: 10;
}
1
2
3
4
5
6
7
8
/* app.java */
// you'll have to add it to the scene and assign it to each object
Button b = new Button();
b.setStyleClass("button");

//put button in a pane and whatnot here
Scene scene = new Scene(pane, 300, 200);
scene.getStyleSheets().add("stylesheet.css")

And that’s pretty much everything I have to say regarding JavaFX. There’s certainly still much more I have to know about though.