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)
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.
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.
Yes, of course. The simplest thing to do is just to launch this on a separate thread: Process p = Runtime. getRuntime().
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]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With