Skip to Content

MVC in JavaFX: The Internet is Wrong!

MVC, or Model-View-Controller, is an architectural pattern (or a design pattern) that is heavily used in interactive (namely GUI) applications. You find plenty of reading on it, but one of the main ideas behind MVC is that you separate your domain code from your interaction code. This means that your code that is managing your problem domain data and solving your problem domain computations is completely separate and independent of your GUI code. Your GUI must depend on the GUI libraries and frameworks that it is using, and so the MVC idea is to keep that dependency localized.

This is a very good idea. However, the user’s view must stay in sync with the model data, and each time the model’s data changes, the view probably needs updated. And it is a bad idea to have duplicate data for the view.

Because of this, modern GUI frameworks like JavaFX support very tight integrations between the GUI view and the model data. In JavaFX this is done with beans, properties, and observables. The idea of beans has been around a long time in Java, but basically they are objects that have visible properties. Properties are attributes that appear as data values but could have more complicated stuff behind them. Observables are things that other objects can observe, and if they change the other objects are notified.

What about MVC and JavaFX? Why is the Internet wrong?

I’ve searched and searched, and basically every example I can find on the Internet says that when creating your Model classes for a JavaFX application, you should use Properties for your data, so that your JavaFX View can easily be integrated with them. For example, see this example, and another, and even another.

Indeed the API documentation itself implies that this is a good idea (also here).

But what is at the top of the example Model class source code? It’s this:

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;

public class TemperatureModel
{...}

Immediately the Model code depends on JavaFX!!! This is terrible, and entirely defeats the purpose of the MCV design pattern.

Somebody asked this a long time ago, and the answer is still to be determined…

So what can be done?

Firstly, do not make your Model classes dependent on JavaFX. Write plain old Java code that implements your problem domain data management and operations. For the data that will need reflected in a user view, instead of declaring it private, declare it protected.

Secondly, add a changed() method to every model class that has to be reflected in the user view. This should be declared protected and should be an empty method body in the model class. Inside the class, everywhere that the object is updated and its data is modified, call this method (after all grouped changes have been done).

Thirdly, create a subclass of each model class that needs reflected in the user view. This subclass should use JavaFX properties and observables to enable the JavaFX widgets to be connected to the model data. These might have complicated bindings to some of the model data, but also might have some simpler bindings for discrete basic data types (numbers, strings).

Fourthly, override the changed() method in the subclass, and use this to cause the View to be updated whenever the object is changed.

This idea is using inheritance to implement what is known as the Model-View-ViewModel (MVVM) design pattern, which is a variant of MVC. A good discussion, including links to the history of MVVM, can be found here, although that page seems to not use inheritance between the Model and ViewModel.

A Simple Example

The official OpenJFX TableView API documentation uses a Person model class as an example, and it is entirely dependent on JavaFX and so is not a good MVC example. Below is a refactoring of this class into a pure Model class, and a JavaFX viewable subclass. The entire example JavaFX application is on GitHub.

Person class (pure model class)

//
// Pure Model class Person with no JavaFX dependencies
// - Model classes in an MVC architecture should have
//   absolutely no dependencies to any GUI libraries
//
public class Person
{

protected String firstName;
protected String lastName;

public Person(String firstName, String lastName)
{
    this.firstName = firstName;
    this.lastName = lastName;
}

public void capitalize()
{
    lastName = lastName.toUpperCase();
    System.out.println("changed to " + lastName);
    changed();
}

// invoke this whenever object is changed; view
// subclass will override it so that view GUI can change
protected void changed()
{}

}

JavaFX Person Subclass:

//
// JavaFX specific subclass for our Model class Person
// - this subclass should be considered as part of the
//   View in an MVC architecture
//
import javafx.beans.property.StringProperty;
import javafx.beans.property.SimpleStringProperty;

public class FXPerson extends Person
{
public StringProperty firstNameProp;
public StringProperty lastNameProp;

public FXPerson(String firstName, String lastName)
{
    super(firstName, lastName);
    firstNameProp = new SimpleStringProperty(this, "firstName", this.firstName);
    lastNameProp = new SimpleStringProperty(this, "lastName", this.lastName);
}

public StringProperty firstNameProperty() {
    return firstNameProp;
}

public StringProperty lastNameProperty() {
    return lastNameProp;
}

// we update the viewable properties when we know
// the object has changed
@Override
protected void changed()
{
    firstNameProp.setValue(firstName);
    lastNameProp.setValue(lastName);
}

}