Over a million developers have joined DZone.

Building Reactive Systems with JavaFX

JavaFX is a new library for composing graphical Java apps. Here's how to build a reactive system with Java FX!

· Java Zone

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

JavaFX is the new standard library for building graphical applications in Java, but many programmers out there is still stuck with Swing or even (tremble) AWT. Here are a few tips on how you can use many of the new awesome features in the JavaFX toolkit to build reactive and fast applications!

1. Property Values

If you have snooped around in the JavaFX components you must have come across the term Property. Almost every value in the FX library can be observed, the width of a divider, the size of an image, the text in a label, the children of a list as well as the status of a checkbox. Properties come in two categories; Writables and Readables. A writable value can be changed either using a setter or by directly modifying the property. JavaFX will handle the event processing and make sure every component that depends on the property will be notified. A readable value has methods that allow you to receive notifications when the value changes.

Example:

// Read- and writable
StringProperty name = new SimpleStringProperty("Emil"); 
// Only readable
ObservableBooleanValue nameIsEmpty = name.isEmpty();

2. Binding values

When you have a writable and a readable value, you can start defining rules for how these values relate. A writable property can be bound to a readable property so that its value will always match the readable one. Bindings are not immediate, but they will be resolved before the values are observed (see what I did there). Bindings can be unidirectional or bidirectional. Of course, if they are bidirectional, both properties will need to be writable.

Example:

TextField fieldA = new TextField();
TextField fieldB = new TextField();
fieldA.prefWidthProperty().bind(fieldB.widthProperty());

3. Observable Lists

Properties are not the only thing that can be observed. The members of a list can also be observed if the list is wrapped in an ObservableList. The reaction model of the ObservableList is quite advanced. Not only can you receive a notification when the list is modified, you can also see exactly how the list was changed.

Example:

List<String> otherList = Arrays.asList("foo", "bar", "bar");
ObservableList<String> list = FXCollections.observableList(otherList);

list.addListener((ListChangeListener.Change<? extends String> change) -> {
    System.out.println("Received event.");
    while (change.next()) {
        if (change.wasAdded()) {
            System.out.println(
                "Items " + change.getAddedSubList() + " was added.");
        }

        if (change.wasRemoved()) {
            System.out.println(
                "Items " + change.getRemoved() + " was removed.");
        }
    }
});

System.out.println("Old list: " + list);
list.set(1, "foo");
System.out.println("New list: " + list);

The output from the above is:

Old list: [foo, bar, bar]
Received event.
Items [foo] was added.
Items [bar] was removed.
New list: [foo, foo, bar]

As you can see, the set operation only created one event.

4. StringConverter

Sometimes, you will find that you don’t have the exact value in a component as you need to create a binding. A typical example of this is that you have a StringProperty with the path that you have gotten from a TextField. If you want an observable property with this value expressed as a Path, you will need to create a StringConverter for that.

Example:

TextField fileLocation = new TextField();
StringProperty location = fileLocation.textProperty();
Property<Path> path = new SimpleObjectProperty<>();

Bindings.bindBidirectional(location, path, new StringConverter<Path>() {
    @Override
    public String toString(Path path) {
        return path.toString();
    }

    @Override
    public Path fromString(String string) {
        return Paths.get(string);
    }
});

The object property is not bound bidirectionally to the textfield value.

5. Expressions

Using the Bindings-class shown before you can create all kinds of expressions. Say that you have two textfields that the user can enter information into. You now want to define a read-only field that always contains a string that if the two string lengths are equal, expresses the character by character mix between the two. If the lengths are not equal, a helping message should be shown instead.

Example:

TextField first  = new TextField();
TextField second = new TextField();
TextField mix    = new TextField();

mix.textProperty().bind(
    Bindings.when(
        first.lengthProperty().isEqualTo(second.lengthProperty())
    ).then(Bindings.createStringBinding(
        () -> {
            int length        = first.lengthProperty().get();
            String firstText  = first.textProperty().get();
            String secondText = second.textProperty().get();
            char[] result     = new char[length * 2];

            for (int i = 0; i < length; i++) {
                result[i * 2]     = firstText.charAt(i);
                result[i * 2 + 1] = secondText.charAt(i);
            }

            return new String(result);
        }, 
        first.textProperty(),
        second.textProperty()
    )).otherwise("Please enter two strings of exactly the same length.")
);

Conclusion

These were only a handful of the many features of JavaFX. Hopefully you can find many more creative ways of utilizing the event system!

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:
bindings ,javafx ,reactive ,user interface ,ui ,programming ,java ,events

Published at DZone with permission of Emil Forslund, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}