Book Image

Mastering JavaFX 10

By : Sergey Grinev
5 (1)
Book Image

Mastering JavaFX 10

5 (1)
By: Sergey Grinev

Overview of this book

: JavaFX 10 is used to create media-rich client applications. This book takes you on a journey to use JavaFX 10 to build applications that display information in a high-performance, modern user interface featuring audio, video, graphics, and animation. Mastering JavaFX 10 begins by introducing you to the JavaFX API. You will understand the steps involved in setting up your development environment and build the necessary dependencies. This is followed by exploring how to work with the assets, modules, and APIs of JavaFX. This book is filled with practical examples to guide you through the major features of JavaFX 10. In addition to this, you will acquire a practical understanding of JavaFX custom animations, merging different application layers smoothly, and creating a user-friendly GUI with ease. By the end of the book, you will be able to create a complete, feature-rich Java graphical application using JavaFX.
Table of Contents (15 chapters)

Application and JavaFX subsystems

The very first API, javafx.application.Application, represents the program itself. It prepares everything for us to start using JavaFX and is an entry point for all standalone JavaFX applications. It does the following:

  • Initializes JavaFX toolkit (subsystems and native libraries required to run JavaFX)
  • Starts JavaFX Application Thread (a thread where all UI work happens) and all working threads
  • Constructs the Application instance (which provides a starting point for your program) and calls the user-overridden methods
  • Handles application command line parameters
  • Handles all cleanup and shutdown once the application ends

Let's look closely at each of these steps.

Components of the JavaFX toolkit

JavaFX toolkit is the stuff hidden under the hood of the JavaFX. It's a set of native and Java libraries that handles all the complexity of the drawing UI objects, managing events, and working with various hardware. Luckily, they are well-shielded by the API from the user. We will have a brief overview of the major components. It can be useful, for example, during debugging your application; by knowing these component names, you will be able to identify potential problems from stack traces or error messages.

Glass toolkit

This toolkit is responsible for low-level interaction with operating systems. It uses native system calls to manage windows, handle system events, timers, and other components.

Note that Glass is written from scratch; it doesn't use AWT or Swing libraries. So, it's better to not mix old Swing/AWT components and JavaFX ones for the sake of performance.

Prism and Quantum Toolkit

Prism renders things. It was optimized a lot over the course of JavaFX releases. Now, it uses hardware acceleration and software libraries available in the system such as DirectX or OpenGL. Also, Prism renders concurrently and also can render upcoming frames in advance while current frames are being shown, which gives a large performance advantage.

Quantum Toolkit manages the preceding Prism, Glass, and JavaFX API and handles events and rendering threads.

Media

This framework is responsible for video and audio data. In addition to playback functionality, JavaFX Media provides advanced functionality—for example, buffering, seeking, and progressive downloading.

For better performance, Media uses the separate thread, which is synchronized with frames, prepared by Prism, to show/play relevant media data using the correct framerate.

WebView/WebEngine

WebView is a web rendering engine based on the OpenSource WebKit engine, it supports the majority of modern HTML features.

Using WebView, you can incorporate any web resources or even whole sites into your JavaFX applications and integrate them with modern web tools, such as Google Maps.

Working with JavaFX Application Thread

Despite the development of the technology, building a thread-safe UI toolkit is still an enormous challenge due to the complexity of the events and state handling. JavaFX developers decided to follow Swing pattern, and instead of fighting endless deadlocks proclaimed that everything in the UI should be updated from and only from a special thread. It's called JavaFX Application Thread.

For simple programs, you don't notice this requirement, as common JavaFX program entry points are already run on this thread.

Once you started adding multithreading to your application, you will need to take care of the thread you use to update the UI. For example, it's a common approach to run a lengthy operation on the separate thread:

new Thread(() -> {
//read myData from file
root.getChildren().add(new Text(myData));
}).start();

This code tries to access JavaFX UI from a common Thread, and it will lead to:

java.lang.IllegalStateException: Not on FX application thread

To address that, you need to wrap your JavaFX code in the next construction:

Platform.runLater(()-> {
root.getChildren().add(new Text("new data"));
});
Note that you can not construct UI objects on JavaFX Application Thread. But, once you have showed them to the user you need to follow the JavaFX UI Thread rule.

Also, note that having one thread for the update UI means that while you run your code on this thread nothing is being updated, and the application looks frozen for the user. So, any long computational, network, or file-handling tasks should be run on a regular thread.

If you need to check in your code which thread you are on, you can use the following API:

boolean Platform.isFxApplicationThread();

Application class

The most common way to use the JavaFX API is to subclass your application from the javafx.application.Application class. There are three overridable methods in there:

  • public void init(): Overriding this method allows you to run code before the window is created. Usually, this method is used for loading resources, handling command-line parameters, and validating environments. If something is wrong at this stage, you can exit the program with a friendly command-line message without wasting resources on the window's creation.
Note this method is not called on JavaFX Application Thread, so you shouldn't construct any objects that are sensitive to it, such as Stage or Scene.
  • public abstract void start(Stage stage): This is the main entry point and the only method that is abstract and has to be overridden. The first window of the application has been already prepared and is passed as a parameter.
  • public void stop(): This is the last user code called before the application exits. You can free external resources here, update logs, or save the application state.

The following JavaFX code sample shows the workflow for all these methods:

Note the comment in the first line—it shows the relative location of this code sample in our book's GitHub repository. The same comment will accompany all future code samples, for your convenience.
// chapter1/HelloFX.java
import javafx.application.Application;
import javafx.scene.*;
import javafx.stage.Stage;

public class FXApplication extends Application {

@Override
public void init() {
System.out.println("Before");
}

@Override
public void start(Stage stage) {
Scene scene = new Scene(new Group(), 300, 250);
stage.setTitle("Hello World!");
stage.setScene(scene);
stage.show();
}

public void stop() {
System.out.println("After");
}
}

Note that you don't need the main() method to run JavaFX. For example, this code can be compiled and run from the command line:

> javac FXApplication.java
> java FXApplication

It shows a small empty window:

Using the Application.launch() method

If you need to have control over the moment JavaFX starts, you can use the Application.launch() method:

public static void main(String[] args) {
// you custom code
Application.launch(MyApplication.class, args);
}

Here, MyApplication should extend javafx.application.Application.

Managing command-line parameters

Unlike the regular Java programs, which receive all parameters in the main(String[] args) method, JavaFX provides an extra API to get them: Application.getParameters(). Then, you can access them next categories:

  • raw format: without any changes
  • parsed named pairs: only parameters which were formatted as Java options: --name=value. They will be automatically built into a name-value map.
  • unnamed: parameters which didn't fit into the previous category.

Let's compile and run a program with next demo parameters (run these commands from Chapter1/src folder of book's GitHub repository):

javac FXParams.java
java FXParams --param1=value1 uparam2 --param3=value3

This will run next code, see the corresponding API calls in bold:

// FXParams.java
System.out.println("== Raw ==");
getParameters().getRaw().forEach(System.out::println);
System.out.println("== Unnamed ==");
getParameters().getUnnamed().forEach(System.out::println);
System.out.println("== Named ==");
getParameters().getNamed().forEach((p, v) -> { System.out.println(p + "=" +v);});

JavaFX will parse these parameters and allocated them into categories:

== Raw ==
--param1=value1
uparam
--param3=value 3
== Unnamed ==
uparam
== Named ==
param3=value 3
param1=value1

Closing the JavaFX application

Usually, the JavaFX application closes once all of its windows (Stages) are closed.

You can close the application at any moment by calling javafx.application.Platform.exit().

Don't call System.exit() as you may be used to doing in Java programs. By doing that you break the JavaFX application workflow and may not call important logic written in on close handlers such as Application.stop().

If you don't want your application to automatically close, add the following code at the beginning of your program:

javafx.application.Platform.setImplicitExit(false);