![](/img/trans.png)
[英]Bind ObservableList<TextField> to ListProperty<String> JFX
[英]How to bind a List<String> to a ObservableList<String>?
我有一個包含List<String>
的 object Bean
。 我想將此列表“綁定”到ObservableList
,以便在將項目添加到原始列表或從原始列表中刪除時,更新ObservableList
(然后觸發監視ObservableList
的偵聽器)。
我發現了這個問題,它的答案顯示了如何使用JavaBeanStringPropertyBuilder
將一個簡單的String
包裝到一個 JavaFX StringProperty
中。
我嘗試做同樣的事情,但將String
替換為List<String>
,如下所示:
public class Bean {
private final List<String> nameList;
private final PropertyChangeSupport propertySupport ;
public Bean() {
this.nameList = new ArrayList<>();
this.propertySupport = new PropertyChangeSupport(this);
}
public List<String> getNameList() {
return nameList;
}
public void setNameList(List<String> nameList)
{
List<String> oldList = new ArrayList<>(this.nameList);
this.nameList.clear();
this.nameList.addAll(nameList);
propertySupport.firePropertyChange("nameList", oldList, this.nameList);
}
public void addName(String name) {
List<String> oldList = new ArrayList<>(this.nameList);
this.nameList.add(name);
propertySupport.firePropertyChange("nameList", oldList, this.nameList);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertySupport.addPropertyChangeListener(listener);
}
}
Bean bean = new Bean();
JavaBeanObjectProperty<List<String>> listProperty = null;
try
{
listProperty = JavaBeanObjectPropertyBuilder.create().bean(bean).name("nameList").build();
} catch (NoSuchMethodException e)
{
throw new RuntimeException(e);
}
listProperty.addListener((ObservableValue<? extends List<String>> obs, List<String> oldName, List<String> newName) ->
{
System.out.println("List changed");
});
bean.setNameList(Arrays.asList("George", "James"));
但是在調用setNameList()
之后沒有觸發監聽器,我不知道我錯過了什么。 請問你能幫幫我嗎?
使用Property<T>
注冊的更改偵聽器只有在屬性值實際更改時才會收到通知。 也就是說, set(T newValue)
方法是這樣實現的:
public void set(T newValue) {
T oldValue = this.get();
if (! oldValue.equals(newValue)) {
// notify change listeners...
}
}
JavaBeanObjectPropertyBuilder
將創建一個JavaBeanObjectProperty<List<String>>
( Property<List<String>>
的實現)並將其值設置為調用bean.getNameList()
的結果。 即bean.nameList
listProperty
引用。
JavaBeanObjectProperty
還通過調用bean.addPropertyChangeListener(...)
注冊了一個監聽器。 什么時候
propertySupport.firePropertyChange("nameList", oldList, this.nameList);
被調用時, JavaBeanObjectProperty
中的內部偵聽器會將其自己的值設置為屬性更改支持觸發的新值; 即它會打電話
set(bean.nameList);
但是,由於這只是對屬性當前值的引用,因此不會通知注冊到listProperty
的更改偵聽器(基本上沒有發生更改)。
澄清一下,如果有幫助: listProperty.get()
返回的List<String>
的內容將在您調用時更改
this.nameList.clear();
和
this.nameList.addAll(nameList);
在bean
中(因為listProperty
引用了bean.nameList
),但實際的列表引用本身並沒有改變。
你可以測試這個,例如
Bean bean = new Bean();
JavaBeanObjectProperty<List<String>> listProperty = null;
try
{
listProperty = JavaBeanObjectPropertyBuilder.create().bean(bean).name("nameList").build();
} catch (NoSuchMethodException e)
{
throw new RuntimeException(e);
}
listProperty.addListener((ObservableValue<? extends List<String>> obs, List<String> oldName, List<String> newName) ->
{
System.out.println("List changed");
});
List<String> oldList = listProperty.get();
bean.setNameList(Arrays.asList("George", "James"));
List<String> newList = listProperty.get();
System.out.println(oldList);
System.out.println(newList);
System.out.println(oldList == newList);
最好的解決方法是簡單地在Bean
class 中使用ObservableList
:
public class Bean {
private final ObservableList<String> nameList;
public Bean() {
this.nameList = FXCollections.observableArrayList<>();
}
public ObservableList<String> getNameList() {
return nameList;
}
public void addName(String name) {
this.nameList.add(name);
}
}
請注意,您不會失去setNameList(...)
提供的功能; 你可以做
bean.getNameList().setAll(...);
如果要設置列表的全部內容。 如果您想要相同的 API,您可以使用ListProperty
而不是ObservableList
。
然后你的測試代碼就變成了
Bean bean = new Bean();
bean.getNameList().addListener((ListChangeListener.Change<? extends String> change) ->
{
System.out.println("List changed");
});
bean.getNameList().setAll("George", "James");
正如問題的評論中所述,我真的不明白有任何限制阻止在 model 中使用ObservableList
; 事實上,這正是設計ObservableList
(以及屬性和綁定 API)的用例。
沒有像 Java 用於簡單屬性的 Bean 適配器那樣設計用於可觀察列表的適配器。 因此,如果您真的想避免在 model class 中使用ObservableList
(同樣,這對我來說真的沒有意義),您必須為Bean
實現自己的偵聽器通知:
public class Bean {
private final List<String> nameList ;
private final List<Consumer<String>> nameAddedListeners ;
private final List<Consumer<List<String>>> nameListReplacedListeners ;
public Bean() {
this.nameList = new ArrayList<>();
this.nameAddedListeners = new ArrayList<>();
this.nameListReplacedListeners = new ArrayList<>();
}
public List<String> getNameList() {
return nameList ;
}
public void setNameList(List<String> newNames) {
this.nameList.setAll(newNames);
nameListReplacedListeners.forEach(listener -> listener.accept(newNames));
}
public void addName(String name) {
this.nameList.add(name);
nameAddedListeners.forEach(listener -> listener.accept(name));
}
public void addNameListReplacedListener(Consumer<List<String>> listener) {
nameListReplacedListeners.add(listener);
}
public void addNameAddedListener(Consumer<String> listener) {
nameAddedListeners.add(listener);
}
}
現在你可以做
Bean bean = new Bean();
bean.addNameListReplacedListener(list -> System.out.println("Names changed"));
bean.setNameList(List.of("George", "James"));
或者您可以有效地創建一個適配器:
Bean bean = new Bean();
ObservableList<String> names = FXCollections.observableArrayList(bean.getNameList());
bean.addNameAddedListener(names::add);
bean.addNameListReplacedListener(names::setAll);
等等
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.