Skip to content

Getting Started HelloWorld (english)

Jorge Branco edited this page Jan 14, 2019 · 14 revisions

This tutorial shows how to implement a simple helloWorld application with mvvmFX.

Prerequisites

  • Maven
  • Oracle JDK version 8 or higher (OpenJDK won't work at the moment because there is no JavaFX included)
  • a Java IDE of your choice
  • (optional) JavaFX SceneBuilder

1. Create maven project

In this tutorial we use Maven for handling our build process and managing our dependencies. At first we create a maven project for the example. Create a file POM.xml in your project folder. In the POM.xml file we add the dependency to mvvmFX and change the java version.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>mvvmfx-helloworld</artifactId>
    <version>1.0.0</version>
    <name>HelloWorld Example</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>de.saxsys</groupId>
            <artifactId>mvvmfx</artifactId>
            <version>1.5.2</version>
        </dependency>
    </dependencies>

</project>

In addition we have to create the typical maven folder structure like this:

project_directory
   +--src
   |   +--main
   |       +--java
   |       +--resources
   +--POM.xml 

2. JavaFX starter class

We start with a java class to launch the application. In this example we use the package com.example.helloworld. We name the class Starter and add a main method. Additionally we extend from javafx.application.Application to define the entry point into our JavaFX application.

public class Starter extends Application{
    public static void main(String...args){
        Application.launch(args);
    }

    @Override
    public void start(Stage stage){
        stage.setTitle("Hello World Application");
        stage.show();
    }
}

This easy example can already be started. An empty window is shown with "Hello World Application" in the title bar.

3. Create the UI

There are two options to create a user interface with JavaFX: You can create ui elements and put them together in java code like it was done in the old days with Java Swing. The alternative and in most cases the better choice is to use FXML, a XML dialect to describe the JavaFX UI.

One of the reasons to use FXML is the really cool JavaFX SceneBuilder. It is a graphical UI builder which can be used to click FXML files realy fast. It is open-source an can be downloaded here.

MvvmFX supports Views both based on FXML and directly written with Java code. But in this tutorial we will stay with the FXML option.

When FXML is used the conceptual "View" consists of two files:

  1. The FXML file contains the structure and layout of the UI. It defines what UI controls are used.
  2. A so called "CodeBehind" class or "View class". This is a Java class that contains references to UI controls from the FXML file. This is needed so that we can access the controls that are defined in the FXML file from Java code.

Both files together are "the View". MvvmFX uses a convention-over-configuration approach with some Naming-Conventions. Simply speaking: Both the FXML file and the CodeBehind class should have the same name (without file extension) and should be located in the same folder/package.

ViewModel

Before we create our View files, we begin with the ViewModel class. In the first place this class will be empty but we are coming back here in a few minutes. We name this class HelloWorldViewModel and implement the interface de.saxsys.mvvmfx.ViewModel.

public class HelloWorldViewModel implements ViewModel {
}

View

Now we create our view class HelloWorldView. This class implements the interface de.saxsys.mvvmfx.FxmlView. Additionally we need to provide the type of our ViewModel class as generic type. This way the logical connection between the View and ViewModel is established. In this example we implement the interface Initializeable too. This interface is part of JavaFX and requires you to implement a method initialize that will be called after the view is completely loaded.

public class HelloWorldView implements FxmlView<HelloWorldViewModel>, Initializable {
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
    }
}

FXML

Now we can create our FXML file. Like said before we follow the naming conventions and name the file HelloWorldView.fxml and put it into the same directory like the View class.

Note for Maven: Maven has different directories for Java classes (src/main/java) and other resources (src/main/resources). FXML files need to be placed inside this src/main/resources directory to be handled correctly. But it's still important to satisfy the conventions by putting the file into the same package as the View class. This means that you have to create the same package/directory structure under src/main/resources. In our example we put the FXML file in src/main/resources/com/example/helloworld/ because our View class has the full qualified name com.example.helloworld.HelloWorldView.

Alternatively, we can add the following configuration to our POM.xml file. This way we can put our FXML files in the same folder as our java code:

<project ...>
...
<build>
 <resources>
   <resource>
     <directory>src/main/java</directory>
     <includes>
       <include>**/*.fxml</include>
     </includes>
   </resource>
 </resources>
 ...
</build>
...
</project>

We could design our FXML file with SceneBuilder or by hand with a XML editor. At first we add a Label with the text "HelloWorld" and put it into a VBox. It's important that we add a reference to our View class with the fx:controller attribute.

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox xmlns:fx="http://javafx.com/fxml" alignment="CENTER"
	fx:controller="com.example.helloworld.HelloWorldView">
  <children>
    <Label text="Hello World" />
  </children>
  <padding>
    <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
  </padding>
</VBox>

4. Edit Starter and load the mvvmFX view.

To make the view visible we need to load it and put it into the scene graph of our application. To do this we use the fluent api that is provides by mvvmFX. The FluentViewLoader class gets the view class as parameter and returns a so called ViewTuple. This is a wrapper class that contains the loaded View class /CodeBehind, the viewModel and the root element of the FXML file.

@Override
public void start(Stage stage){
    stage.setTitle("Hello World Application");

    ViewTuple<HelloWorldView, HelloWorldViewModel> viewTuple = FluentViewLoader.fxmlView(HelloWorldView.class).load();

    Parent root = viewTuple.getView();
    stage.setScene(new Scene(root));
    stage.show();
}

5. Edit the ViewModel

At the moment the text message is hardcoded in the FXML file. But the design pattern Model-View-ViewModel says that the state of the View has to be placed in the ViewModel. Let's edit our example to accomplish this.

In the ViewModel we add a StringProperty named "helloMessage" with the initial value "Hello World" together with the getters and setters according to the JavaFX bean conventions.

public class HelloWorldViewModel implements ViewModel {

    private StringProperty helloMessage = new SimpleStringProperty("Hello World");

    public StringProperty helloMessageProperty(){
        return helloMessage;
    }

    public String getHelloMessage(){
        return helloMessage.get();
    }

    public void setHelloMessage(String message){
        helloMessage.set(message);
    }
}

The connection between the label in the FXML file and the StringProperty in the ViewModel is done in the View class. To do this we need to add an attribute fx:id to the label in the FXML file.

<Label fx:id="helloLabel"/>

Please note: In fxml there are the attributes "id" and "fx:id" with different meanings. The "id" attribute without the "fx" namespace prefix is mainly used for styling with CSS. For our objective we need the attribute "fx:id". It's possible to use both attributes together without problems. It's probably a good idea to give both attributes the same value to minimize confusion.

In the view class we can now access the label instance. We add an instance variable of the type Label and are using the variable name "helloLabel". The name is important: JavaFX is doing the association of elements in the FXML file and the View class by matching the "fx:id" attribute value with the names of the instance variables. Additionally we need to add the annotation javafx.fxml.FXML to our instance variable.

In the initialize method of our View class that we have left empty in the first place we can now connect the label with our ViewModel.

To get an instance of the ViewModel into our View we need add an instance variable of the ViewModel type (in our case HelloWorldViewModel) and add the mvvmFX specific annotation de.saxsys.mvvmfx.InjectViewModel. Now the framework can do it's work and provide you the ViewModel instance you need:

public class HelloWorldView implements FxmlView<HelloWorldViewModel>, Initializable  {

    @FXML
    private Label helloLabel;

    @InjectViewModel
    private HelloWorldViewModel viewModel;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        helloLabel.textProperty().bind(viewModel.helloMessageProperty());
    }
}

In the initialize method we use Data-Binding to connect the label and the ViewModel: The line helloLabel.textProperty().bind(viewModel.helloMessageProperty()); means that we take the text property of the label and bind it's value to the "helloMessage" StringProperty of the ViewModel. This way the label will always show the exact value of this property in the ViewModel. Would we change the value in the ViewModel it would be automatically and immediately changed in the UI. The initial value of the property in the ViewModel was "Hello World" so this value will be visible in the UI at the moment.

You can find the complete code of this example under: helloworld

There is also a variant of this example that doesn't use FXML but the classical java-code way of creating UIs here: helloworld-without-fxml