Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Independent JavaFX properties implementation?

Java FX properties is a nice API allowing the developer to create properties instead of using standard get/set method semantics. It also adds subscription to changes, properties expressions support for basic types and collections. Though properties are there in C# as a part of the language, these properties are available only inside the JavaFX container. I.e. if you try listening to changes, you'll run into an IllegalStateException saying that you need to run your listener code inside the main JavaFX thread.

So is there an alternative available for the rest of the Java world?

Update

Here is an example of an IllegalStateException. Am I misusing JavaFX API?

public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("s1");
        list.add("s2");

        ObservableList<String> observableList = FXCollections.observableList(list);
        observableList.addListener(new ListChangeListener<String>() {
            @Override
            public void onChanged(Change<? extends String> change) {
                System.out.println("added: " + change.getAddedSubList());
            }
        });

        observableList.add("s3");
    }
}

Exception:

Exception in thread "main" java.lang.IllegalStateException
    at com.sun.javafx.collections.NonIterableChange.checkState(NonIterableChange.java:101)
    at com.sun.javafx.collections.NonIterableChange.getPermutation(NonIterableChange.java:81)
    at javafx.collections.ListChangeListener$Change.wasPermutated(ListChangeListener.java:156)
    at javafx.collections.ListChangeListener$Change.getAddedSubList(ListChangeListener.java:212)
    at Test$1.onChanged(Test.java:23)
    at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:134)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:48)
    at com.sun.javafx.collections.ObservableListWrapper.callObservers(ObservableListWrapper.java:97)
    at com.sun.javafx.collections.ObservableListWrapper.add(ObservableListWrapper.java:154)
    at com.sun.javafx.collections.ObservableListWrapper.add(ObservableListWrapper.java:144)
    at Test.main(Test.java:27)
like image 389
Andrey Chaschev Avatar asked Oct 23 '13 18:10

Andrey Chaschev


People also ask

Is JavaFX platform independent?

Written in Java − The JavaFX library is written in Java and is available for the languages that can be executed on a JVM, which include − Java, Groovy and JRuby. These JavaFX applications are also platform-independent.

Is JavaFX deprecated?

Starting with JDK 11, Oracle will remove JavaFX from the JDK, though will continue to provide commercial support for it in Oracle JDK 8 at least until 2022, according to Oracle's blog.

Does JavaFX run on a separate thread?

Yes, of course. The simplest thing to do is just to launch this on a separate thread: Process p = Runtime. getRuntime().


1 Answers

Answer

JavaFX properties can be used independently to the rest of the JavaFX system and there is no requirement that properties on objects that do not effect an active JavaFX Scene Graph have their listener code run on the JavaFX application thread.

Explanation

Running listener code on the JavaFX application thread is only required when the change listeners or bindings effect properties of Nodes in a Scene Graph:

An application must attach nodes to a Scene, and modify nodes that are already attached to a Scene, on the JavaFX Application Thread.

You can write Java programs that use JavaFX properties and have no nodes or scene graph. You can supply properties and change listeners executable on non-JavaFX threads for objects which have no interaction with the scene graph.

Sample

The Oracle JavaFX properties and binding tutorial demonstrates use of JavaFX properties in programs which use no other JavaFX components and have no JavaFX application thread.

Additional sample based on questions in comments

Thanks, examples in this tutorial work for me. However I tried listening to the ObservableList collection and got this exception. Am I doing something wrong?

You are doing something wrong.

I tried running the sample code you added to your question on Java 8, and the error message is more explicit:

Exception in thread "main" java.lang.IllegalStateException: Invalid Change state: next() must be called before inspecting the Change.

When you add a change.next() call, your test application functions as you would expect.

The javadoc for change.next() reads:

Go to the next change. In initial state is invalid a require a call to next() before calling other methods. The first next() call will make this object represent the first change.

Working sample code:

import javafx.collections.*;
import java.util.*;

public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("s1");
        list.add("s2");

        ObservableList<String> observableList = FXCollections.observableList(list);
        observableList.addListener(new ListChangeListener<String>() {
            @Override
            public void onChanged(Change<? extends String> change) {
                while (change.next()) {
                    System.out.println("added: " + change.getAddedSubList());
                }
            }
        });

        observableList.add("s3");
    }
}

Output of sample code:

added: [s3]
like image 60
jewelsea Avatar answered Oct 05 '22 11:10

jewelsea