12.6. JavaFX 17 Bookmarks and Notes

12.6.1. Packages of Interest

12.6.2. RE: App Class

12.6.3. RE: Scene Graph

  • javafx.scene - (package) Provides the core set of classes for the JavaFX Scene Graph API.

  • javafx.scene.Scene - (class) The container for all content in a scene graph.

  • javafx.scene.Node - (class) Base class for scene graph nodes (e.g., components, etc.).

  • javafx.scene.Group - (class) Light-weight, non-resizable container used for absolute positioning.

12.6.4. RE: Layout Panes

12.6.5. RE: Controls

12.6.6. RE: Event Handling

12.6.7. RE: Menus

12.6.8. RE: Images

12.6.9. RE: Styling and CSS

12.6.10. Including a CSS file

Let’s assume you have a Cascading Style Sheet (CSS) file located at resources/theme-uga.css. In order for the style declarations in that file to affect the nodes in a scene, the file needs to be added to a scene’s collection of stylesheets:

String stylesheet = // replace-me; see below
scene.getStylesheets().add(stylesheet);

Below, we describe two portable ways to refer to resources/theme-uga.css using the stylesheet variable in the example. Please pay attention to the subtle differences between each approach.

  • If resources is in your top-level project directory – for a Maven-based project, this means that resources is directly inside the same directory as the project’s pom.xml file, then you can use "file:resources/theme-uga.css" to refer to theme-uga.css:

    String stylesheet = "file:resources/theme-uga.css";
    scene.getStylesheets().add(stylesheet);
    

    PRO: This will work with or without Maven.

    CON: This will only work if the program is run in the directory immediately above resources. If you try to run the program from some other location, then Java may not be able to find the stylesheet. To remedy this, you will need to add the path to your top-level project directory to the class path (e.g., using -cp).

  • If resources is in src/main (i.e., it’s relative path in your top-level project directory is src/main/resources), then you can use getClass().getClassLoader().getResource("theme-uga.css").toExternalForm() to refer to theme-uga.css:

    String stylesheet = getClass().getClassLoader().getResource("theme-uga.css").toExternalForm();
    scene.getStylesheets().add(stylesheet);
    

    PRO: This will work even when packaged into a JAR file.

    CON: It’s clunky. While Maven will add src/main/resources to the class path, you may need to manuall add that directory to the class path if running without Maven.

The next example shows what theme-uga.css might look like. It declares some reusable color variables in the .root declaration, then it declares that all rendered Rectangle objects should have their fill color set to Lake Herrick blue.

.root {
    -uga-arch-black: #000000;
    -uga-bulldog-red: #ba0c2f;
    -uga-chapel-bell-white: #ffffff;
    -uga-glory-glory: #e4002b;
    -uga-lake-herrick: #00a3ad;
}

Rectangle {
    -fx-fill: -uga-lake-herrick;
}

NOTE: The base stylesheet that JavaFX automatically loads is called modena.css; you can view it’s contents here.

12.6.11. RE: Timelines

12.6.12. Brief Timeline Explanation

A Timeline object can be used to execute blocks of code or change values (or both) sequentially at specific times and, if configured to do so, repeat the execution of that sequence one or more times (or indefinitely). It has three states: RUNNING, PAUSED, and STOPPED; and it also has a list of KeyFrame objects, each of which has an associated duration specified by its time property.

When a Timeline object is running (e.g., after calling its play() method), it generates ActionEvent objects for each KeyFrame; the generation of these events triggers the sequential execution of any associated event handlers on the JavaFX Application Thread (JFXAT).

A KeyFrame may have a user-defined event handler or a key value (or both). It’s common to see code in the wild that changes the value of a JavaFX property object based on the key values associated with key frames in a Timeline.

12.6.13. Timeline Example

Here is an example that prints the current time (using LocalTime) to standard output every two (2) seconds (specified using Duration), indefinitely:

EventHandler<ActionEvent> handler = event -> System.out.println(LocalTime.now());
KeyFrame keyFrame = new KeyFrame(Duration.seconds(2), handler);
Timeline timeline = new Timeline();
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.getKeyFrames().add(keyFrame);
timeline.play(); // change to RUNNING

The Timeline object also hase a pause method to pause the execution of the timeline. Remember, JavaFX event handlers are executed on the JavaFX Application Thread (JFXAT).