java - ChangeListener 没有给出正确的旧值

标签 java javafx-8

这是代码:

package sample;

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;

/**
 * Created by IDEA on 29/07/15.
 */
public class ListPropertyTest {
    public static void main(String[] args) {
        ListProperty<String> lp =
                new SimpleListProperty<>(FXCollections.observableArrayList());
        lp.addListener(new ListChangeListener<String>() {
            @Override
            public void onChanged(Change<? extends String> c) {
                while(c.next()) {
                    String action = c.wasPermutated() ? "perm"
                            : c.wasUpdated() ? "upd"
                            : c.wasRemoved() ? "rem"
                            : c.wasAdded() ? "add" : "";
                    System.out.println("Action: " + action);
                    System.out.println("Removed: " + c.getRemoved());
                    System.out.println("Added: " + c.getAddedSubList());
                }
            }
        });

        lp.addListener(new ChangeListener<ObservableList<String>>() {
            @Override
            public void changed(ObservableValue<? extends ObservableList<String>> observable, ObservableList<String> oldValue, ObservableList<String> newValue) {
                System.out.println("List changed.");
                System.out.println("Old: " + oldValue);
                System.out.println("New: " + newValue);
            }
        });

        lp.addListener(new InvalidationListener() {
            @Override
            public void invalidated(Observable observable) {
                System.out.println("List invalid");
            }
        });

        System.out.println("Add =========");
        lp.addAll("one", "two");
        System.out.println("Set =========");
        lp.set(FXCollections.observableArrayList("two", "three"));
        System.out.println("Remove ============");
        lp.remove("two");
    }
}

结果:

Add =========
List invalid
List changed.
Old: [one, two]
New: [one, two]
Action: add
Removed: []
Added: [one, two]
Set =========
List invalid
List changed.
Old: [one, two]
New: [two, three]
Action: rem
Removed: [one, two]
Added: [two, three]
Remove ============
List invalid
List changed.
Old: [three]
New: [three]
Action: rem
Removed: [two]
Added: []

如您所见,更改监听器仅在“Set”部分中行为正确。

最佳答案

这大部分是有意的行为。

一个ListProperty既是 ObjectProperty<ObservableList>和一个ObservableList

成为ObjectProperty<ObservableList>意味着它包裹(包含对ObservableList的引用)并且有setValue(ObservableList) (或 set(...) )和 getValue()方法。作为ObjectProperty<ObservableList> ,您可以注册一个ChangeListener<ObservableList>用它。如果对包装列表的引用发生变化,由某人调用 setValue(ObservableList)ChangeListener<ObservableList>.changed(...)方法在任何已注册的 ChangeListener 上被调用,传入对 ListProperty 的引用本身,旧的ObservableList引用,和新的ObservableList引用。当您调用 set 时,您会看到此行为在您的代码中。

但是,当您只是更改列表的内容时,包装的列表仍然是相同的物理对象。所以“旧名单”和“新名单”是一回事。这是一个bug在这种情况下,更改监听器会触发通知;向@kleopatra 指出这一点致敬。

一个ListProperty还实现 ObservableList ,通过委托(delegate) ObservableList对包装列表实例的方法调用。这意味着如果列表的内容发生变化,任何ListChangeListener已注册 ListProperty得到通知。再次注意,在本例中只有一个列表对象;只是内容被修改了。

您可以获得有关 ObservableList 发生的更改的详细信息通过Change对象传递给onChanged(...)方法,正如您在 onChanged 的输出中观察到的那样方法。请注意c.getFrom()c.getTo()还会为您提供已更改项目的索引。

我几乎从来不需要 ListProperty :在绝大多数用例中,我只需使用简单的 ObservableList 就足够了执行。基于对象列表的控件(例如 ListViewTableView )使用它们,因此您可以调用 setItems(...)传递现有的ObservableList如果您需要,或者(可能更常见)您可以调用 getItems()检索当前列表并修改它。从上面的解释可以看出,ListProperty允许这些控件观察任一类型的变化。但很可能在您自己的代码中,您将使用 ObservableList直接直接使用比使用 ListProperty 更频繁.

关于java - ChangeListener 没有给出正确的旧值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31688493/

相关文章:

java - 在 show() 之前预加载 JavaFX 阶段

java - 如何在 javafx 中获取字体系列和字体样式?

css - 如何去除所选选项卡 Pane 中的蓝色

java - Spring/JPA 多线程死锁

java - 使用 Joda-Time 倒数圣诞节

javafx-2 - 如何在 JavaFX 8 中从 css 文件加载图像

JavaFX有没有更好的方法来获取问号等的键码

java - addToBackStack() 不适用于 getChildFragmentManager()

java - 在 Java 中使用扫描仪

java - 如何设置 LogBack 配置