6

Java FX 属性是一个很好的 API,允许开发人员创建属性而不是使用标准的 get/set 方法语义。它还添加了对更改的订阅、对基本类型和集合的属性表达式支持。尽管属性在 C# 中作为语言的一部分存在,但这些属性仅在 JavaFX 容器中可用。即,如果您尝试收听更改,您会遇到一种IllegalStateException说法,即您需要在 JavaFX 主线程中运行您的侦听器代码。

那么对于 Java 世界的其他部分是否有替代方案?

更新

这是一个示例IllegalStateException。我是否在滥用 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 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)
4

1 回答 1

6

回答

JavaFX 属性可以独立于 JavaFX 系统的其余部分使用,并且不要求不影响活动 JavaFX 场景图的对象的属性在 JavaFX 应用程序线程上运行其侦听器代码。

解释

仅当场景图中节点的更改侦听器或绑定影响属性时,才需要在 JavaFX 应用程序线程上运行侦听器代码:

应用程序必须在 JavaFX 应用程序线程上将节点附加到场景,并修改已附加到场景的节点。

您可以编写使用 JavaFX 属性且没有节点或场景图的 Java 程序。您可以为与场景图没有交互的对象提供属性并更改在非 JavaFX 线程上可执行的侦听器。

样本

Oracle JavaFX 属性和绑定教程演示了在不使用其他 JavaFX 组件且没有 JavaFX 应用程序线程的程序中使用 JavaFX 属性。

基于评论中问题的附加示例

谢谢,本教程中的示例对我有用。但是我尝试收听 ObservableList 集合并得到了这个异常。难道我做错了什么?

你做错了什么。

我尝试在 Java 8 上运行您添加到问题中的示例代码,并且错误消息更加明确:

线程“main”java.lang.IllegalStateException 中的异常:无效的更改状态:必须在检查更改之前调用 next()。

当您添加一个change.next()调用时,您的测试应用程序将按照您的预期运行。

change.next()用于读取的 javadoc :

转到下一个更改。在初始状态下是无效的,需要在调用其他方法之前调用 next()。第一次 next() 调用将使该对象代表第一次更改。

工作示例代码:

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");
    }
}

示例代码的输出:

added: [s3]
于 2013-10-23T20:07:35.427 回答