JavaFX - ObservableList 和列表的项目更改

Dav*_*vid 3 javafx observable

此答案可观察列表提供了解决方案,如果列表元素的属性发生变化,该列表将发送“列表已更新” 通知

就我而言,这种可观察列表的元素(一个Element 类)很复杂,我不喜欢为每个成员变量实现属性。因此,我在Element 类中添加了一个BooleanProperty来指示的变化。


元素类

import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;

public class Element {
    // ...
    private ReadOnlyBooleanWrapper changeIndicatorWrapper;

    public Element() {
        //...
        changeIndicatorWrapper = new ReadOnlyBooleanWrapper(false);
    }

    public ReadOnlyBooleanProperty changeIndicatorProperty() {
        return changeIndicatorWrapper.getReadOnlyProperty();
    }

    public void someMethod() {
        // Some update
        changeIndicatorWrapper.set(!changeIndicatorWrapper.get());
    }
}
Run Code Online (Sandbox Code Playgroud)

可观察列表

ObservableList<Element> elementsObservableList = FXCollections.observableList(
    new ArrayList<>(),
    (Element element) -> new Observable[] { element.changeIndicatorProperty() }
);

elementsObservableList.addListener(new ListChangeListener<Element>() {
    @Override
    public void onChanged(Change<? extends Element> c) {
        System.out.println("CHANGE");
        while(c.next()) {
            if (c.wasUpdated()) {
                for (int i = c.getFrom(); i < c.getTo(); ++i)
                    System.out.println(elementsObservableList.get(i));
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

我的问题是关于这种方法。反复将changeIndicatorProperty设置为 true 不会触发更改事件。所以,我每次都需要反转changeIndicatorProperty 值 changeIndicatorWrapper.set(!changeIndicatorWrapper.get())。很奇怪,不是吗?

我可以以编程方式强制更新事件吗?

fab*_*ian 5

很奇怪,不是吗?

不,这并不奇怪。要触发更改,需要发生更改。如果BooleanProperty确定没有发生任何变化,因此没有通知听众任何事情,这仍然满足 的契约Property

其实 aProperty反正是不需要的。需要的是Observable通知它的观察者。您可以通过使用以下类并调用来做到这一点invalidate

public class SimpleObservable implements Observable {

    private final List<InvalidationListener> listeners = new LinkedList<>();

    @Override
    public void addListener(InvalidationListener listener) {
        listeners.add(listener);
    }

    @Override
    public void removeListener(InvalidationListener listener) {
        listeners.remove(listener);
    }

    public void invalidate() {
        for (InvalidationListener listener : listeners) {
            try {
                listener.invalidated(this);
            } catch (RuntimeException ex) {
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

例子:

public class Element {

    protected final SimpleObservable observable = new SimpleObservable();

    public Observable getObservable() {
        return observable;
    }

    public static <T extends Element> ObservableList<T> observableArrayList() {
        return FXCollections.observableArrayList(e -> new Observable[]{e.observable});
    }

    private void update() {
        observable.invalidate();
    }

    public static void main(String[] args) {
        ObservableList<Element> list = Element.observableArrayList();
        list.addListener((ListChangeListener.Change<? extends Element> c) -> {
            while (c.next()) {
                if (c.wasUpdated()) {
                    System.out.println("update: [" + c.getFrom() + ", " + c.getTo() + ")");
                }
            }
        });
        list.addAll(new Element(), new Element(), new Element());
        list.get(1).update();
    }

}
Run Code Online (Sandbox Code Playgroud)