JavaFX, or how I worked with insufficient documentation for UI design
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 buttonMenu
,MenuItem
andMenuBar
- 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 objectTextField
andTextArea
- places where the user can enter textScrollPane
- provides an area to add items and scroll through in
and some non-control items I used were:
Text
- it’s just textFont
- allows you to set a font and size to a textColor
- also just colorjavafx.scene.shape.*
- the different shapes that can be created, likeRectangles
andCircles
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:
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.