JavaFX Best Practices

Startseite/Future, Tech/JavaFX Best Practices

JavaFX Best Practices

1- Introduction

If you’re willing to create/learn implementing and designing desktop applications with the help of a wide range of interfaces, you definitely want to use JavaFX 2,

one of the most powerful Java libraries !

Starting from a brief history to nicely design your application’s architecture following JavaFX best practices, this article will cover the most important aspects, with some sample code and snippets to help you start and/or dive deeper with JavaFX.

2- Brief History

“In 2008, JavaFX was introduced during JavaOne conference, one year after Oracle.”

It all started in June 2005, after Sun Microsystems acquired SeeBeyond Technology Corporation (STC), where Chris Oliver the inventor of JavaFX Script used to work.

After several releases of JavaFX, Oracle acquired Sun in January 2010, almost two years later Oracle declared the intent to open-source JavaFX.

The scripting syntax for JavaFX was used until the release of JavaFX 2.0 stopping with it the support of JavaFX Script and introducing a new set of Java APIs to its developers eliminating the need to learn a new scripting language in order to use JavaFX.

3- Definitions

a) What is JavaFX

A Java library offering a wide range of interfaces with hardware-accelerated graphics,

2D-3D APIs built in and rich media engine for creating and delivering network aware desktop applications and Rich Internet Apps (RIAs require additional software to be installed like plugins and RIA frameworks) that can run across a wide variety of devices and display information in high performance modern user interface including audio, video, graphics and animation.

b) What is FXML

XML based declarative markup language for designing JavaFX user interface of an application separating it completely from the code logic.

4- JavaFX best practices

To deliver the best functionalities taking into consideration maintainability, loose coupling, usability and testable code, developers should always use the relevant language recommended guidelines.

a)  Structuring the application

JavaFX implies a natural split between the visual part and the logic where the actual implementation of the FXML controller can take different forms.

a.1) Supervising Controller

For simple applications this might be completely sufficient and appropriate. By separating the behavioural complexity from the view it makes the application easier to understand and greatly improves its testability.

a.2) Shared Model

In applications that are more complex and contain multiple views, it is typically much more profitable to introduce some sort of model.

In one variant, the model can be completely passive, containing only the state (properties) of the view to be shared with other views and their controllers.

This eliminates the need of controllers exposing the state of their views to other controllers.

In many cases it may also eliminate the need of controllers knowing each other, removing coupling between them and therefore improving their testability.

In such cases the model is the only communication channel between different entities.

a.3) Presentation Model

If testability is the main driver and writing unit tests involving GUI components is either not desired or difficult, the model can completely take over business logic, becoming a realization of a Presentation Model.

The responsibility of the FXML controller is reduced to a role of a “thin” bridge between the view and the model, which handles all events and updates the view via property bindings.

This approach requires a bit more coding compared to previous scenarios, giving in exchange fully testable business logic, not bound to any graphical components.

b)  Dependency Injection

Used by developers to help them in loose coupling their application’s components and testing each component in isolation.

In order to use dependency injection in the application we need to :

  • Extend the javafx.application.Application & call launch method on that class from the main method. This is the application’s entry point.
  • Instantiate dependency injection container of your choice. E.g. Google Guice or Weld.
  • In the application’s start method, instantiate FXMLLoader and set its controller factory to obtain controllers from the container. Ideally obtain the FXMLLoader from the container itself, using a provider. Then give it an .fxml file resource. This will create the content of the newly created window.
  • Give the Parent object instantiated in the previous step to Stage object (usually called primaryStage) supplies as an argument to the start(Stage primaryStage) method.

Display the primaryStage by calling it’s show() method.

c ) Data Binding

Data binding allows you to synchronise the value of two properties which allows you to update your property with the updated value.

Two types of binding are supported :

  • Unidirectional binding: With unidirectional binding, the binding works in just one direction. For example, if you bind property A to property B, the value of property A changes when property B changes, but not the other way around.
  • Bidirectional binding: With bidirectional binding, the two property values are synchronised so that if either property changes, the other property is automatically changed as well.

Setting up either type of binding, we can simply use bind and bindBiDirectional methods then specifying the property you want to bind to as the argument.

Here’s an example that creates a unidirectional binding on the text property of a label to the text property of a text field, so that the contents of the label always displays the contents of the text field:

lable1.textProperty().bind(text1.textProperty());

With this binding in place, the text displayed by label1 is automatically updated, character by character, when the user types data into the text field.

The following example shows how to create a bidirectional binding between two text fields, named text1 and text2:

text1.textProperty().bindBidirectional(text2.textProperty());

With this binding in place, any text you type into either text field will be replicated automatically in the other.

5- Testing

1- FxJUnit4Runner

It is an extension of standard JUnit test runner that initialises the FX toolkit and, in presence of the @RunInFxThread annotation, runs the corresponding tests in the FX thread.

    @RunWith(FxJUnit4Runner.class)
    public class MainControllerTest {
        @Test
        @RunInFxThread
        public void testCopyMessage() {
            FxmlView mainView = new FxmlView(MainController.class);
            MainController controller = mainView.getController();
            controller.inputTextField.setText("Hello World");
            controller.copyButton.fireEvent(new ActionEvent());
            assertEquals("Hello World", controller.outputLabel.getText());
        }
    }

2- TestFX

Robot-based Java GUI testing frameworks were around since the beginnings of AWT/Swing, but most of them faced two major issues: the tests were usually quite verbose and the graphical components were typically looked up by their location on the screen, making the tests very fragile to even minor changes in the layout.

In contrary TestFX, the most popular testing framework for JavaFX, does not suffer these problems. Like other similar tools, it gives a programmatic control of a “robot” that can be used to click on buttons, type into text components and generally mock user interactions.

However the Fluent API, supported by powerful matchers, allows writing tests that are concise, clean and easy to understand.

Also, rather than relying on a component’s location (although this is also possible), it leverages the usage of CSS IDs and class names, that are natural part of JavaFX interfaces.

    @Test
    public void testDummyTextFile () {
        // given:
        rightClickOn("#desktop").moveTo("New").clickOn("Text Document");
        write("dummyTextFile.txt").push(ENTER);
        // when:
        drag(".file").dropTo("#trash-can");
        // then:
        verifyThat("#desktop", hasChildren(0, ".file"));
    }

Optional (can be added in small boxes) :

Tip 1 : Since JavaFX 1.1, major releases had names based on streets or neighbourhoods in San Francisco.

Tip 2 : February, 2009 was the first release of JavaFX for mobile development (JavaFX 1.2)

Tip 3 : March, 2014 was the release of JavaFX 8 that had support for 3D graphics.

 

15. Oktober, 2018|Kategorien: Future, Tech|0 Kommentare

Über den Autor:

Geteilt