ChangeListener 没有给出正确的旧值
ChangeListener not giving correct old value
代码如下:
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
时,您会看到此行为。
然而,当您简单地更改列表的内容时,包装列表仍然是相同的物理对象。所以 "old list" 和 "new list" 是一回事。在这种情况下,更改侦听器触发通知是 bug;感谢@kleopatra 指出这一点。
A ListProperty
还通过将 ObservableList
方法调用委托给包装列表实例来实现 ObservableList
。这意味着如果列表的内容发生变化,任何在 ListProperty
注册的 ListChangeListener
都会收到通知。再次注意,在这种情况下只有一个列表对象;只是修改了内容
您可以通过传递给 onChanged(...)
方法的 Change
对象获取有关 ObservableList
发生的更改的详细信息,正如您在 [=35= 的输出中观察到的那样] 方法。请注意,c.getFrom()
和 c.getTo()
也会为您提供已更改的项目的索引。
我几乎从来不需要 ListProperty
:在绝大多数用例中,我只使用普通的 ObservableList
实现就足够了。基于对象列表的控件(例如 ListView
和 TableView
)使用它们,因此您可以调用 setItems(...)
以在需要时传入现有的 ObservableList
,或者(可能更常见)你可以调用 getItems()
来检索当前列表并修改它。从上面的解释中可以看出,ListProperty
允许这些控件观察任何一种变化。但很可能在您自己的代码中,您直接使用 ObservableList
的频率远高于使用 ListProperty
.
的频率。
代码如下:
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
时,您会看到此行为。
然而,当您简单地更改列表的内容时,包装列表仍然是相同的物理对象。所以 "old list" 和 "new list" 是一回事。在这种情况下,更改侦听器触发通知是 bug;感谢@kleopatra 指出这一点。
A ListProperty
还通过将 ObservableList
方法调用委托给包装列表实例来实现 ObservableList
。这意味着如果列表的内容发生变化,任何在 ListProperty
注册的 ListChangeListener
都会收到通知。再次注意,在这种情况下只有一个列表对象;只是修改了内容
您可以通过传递给 onChanged(...)
方法的 Change
对象获取有关 ObservableList
发生的更改的详细信息,正如您在 [=35= 的输出中观察到的那样] 方法。请注意,c.getFrom()
和 c.getTo()
也会为您提供已更改的项目的索引。
我几乎从来不需要 ListProperty
:在绝大多数用例中,我只使用普通的 ObservableList
实现就足够了。基于对象列表的控件(例如 ListView
和 TableView
)使用它们,因此您可以调用 setItems(...)
以在需要时传入现有的 ObservableList
,或者(可能更常见)你可以调用 getItems()
来检索当前列表并修改它。从上面的解释中可以看出,ListProperty
允许这些控件观察任何一种变化。但很可能在您自己的代码中,您直接使用 ObservableList
的频率远高于使用 ListProperty
.