Skip to content

Getting Started HelloWorld (english)

Manuel Mauky edited this page Apr 19, 2015 · 14 revisions

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

Prerequisites

  • Maven
  • Java in version 8
  • a Java IDE of your choice
  • (optional) JavaFX SceneBuilder

1. Create maven project

At first we create a maven project for the example. 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>de.saxsys</groupId>
    <artifactId>mvvmfx-helloworld</artifactId>
    <version>1.1.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.1.0</version>
        </dependency>
    </dependencies>

</project>

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

  • src/main/java
  • src/main/resources

2. JavaFX starter class

We start with a java class to launch the application. In this example we use the package de.saxsys.jfx.mvvmfx.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 a View

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 realy good tool JavaFX SceneBuilder which can be used to click you FXML files realy fast.

Since version 0.2.0 of mvvmFX we support Views both based on FXML and directly written with Java code. But in this tutorial we will stay with the FXML option.

For mvvmFX a View consists of a FXML file and a belonging Java class. This Java class is the so called "CodeBehind" part of the View and has to have the same name as the FXML file by convention and has to be placed in the same package as the FXML file.

This conventions enable us to reduce the needed configuration (Convention-Over-Configuration).

ViewModel

We begin with the ViewModel class for our example. In the first place this class will be empty but we are coming back here in a view minutes. We name this class HelloWorldViewModel and implement the interface de.saxsys.mvvmfx.ViewModel. In this class later we will implement the view specific logic but in the first place we let this class be empty.

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 use 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/de/saxsys/jfx/mvvmfx/helloworld/.

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="de.saxsys.mvvmfx.jfx.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 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 showed 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 helloMessage(){
        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 naming of the instance variables. Additionally we need to add the annotation javafx.fxml.FXML.

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 in 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. No our framework can do the 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.helloMessage());
    }
}

In the initialize method we use Data-Binding to connect the label and the ViewModel: The line helloLabel.textProperty().bind(viewModel.helloMessage()); 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 allways 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: mvvmfx-helloworld

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