我有ObservableList<MyElement> list = FXCollections.observableArrayList();
public class MyElement
{
private IntegerProperty position;//with getter
//[...]
//somewhere in the constructor taking the list as argument
position.bind(list.indexOf(this));
}
现在我想将MyElement.position绑定到列表中的实际位置,即如果列表中的位置发生变化(例如在GUI或其他任何内容中拖放)我希望position属性自动更新
这可能吗?我可以在这些值之间建立双向绑定吗?
答案 0 :(得分:2)
我不知道我是否正确理解了你的问题,但我会尽力回答:-)。
问题是,一旦ObservableList(javafx.collections)对象没有存储某种“选定”索引状态,为什么我们应该将另一个整数绑定到它?
我认为,在这种情况下,您的代码应负责存储“选定”索引状态并将其公开给客户端代码。如果这是您正在寻找的,我建议您有三个属性来处理它:
public class ListSelection<T> {
private ObservableList<T> items = FXCollections.observableArrayList(new ArrayList<T>());
private ObjectProperty<T> selectedItem = new SimpleObjectProperty<>();
private IntegerProperty selectedIndex = new SimpleIntegerProperty(0);
}
可以使用selectedIndex
属性控制所选元素。
然后,创建对selectedItem
的绑定,以便在selectedIndex
更改时“自动”更新它:
selectedItem.bind(
when(isEmpty(items))
.then(new SimpleObjectProperty<T>())
.otherwise(valueAt(items, selectedIndex))
);
Bindings
应该是静态导入的:
import static javafx.beans.binding.Bindings.*;
请注意方法Bindings.valueAt(ObservableList<E> list, ObservableIntegerValue index)
的使用。它创建了对list.get(index.getValue())
元素的绑定。
最后,您可以像这样使用它:
ListSelection<String> selection = new ListSelection<>();
Label label = new Label();
List<String> weekDays = Arrays.asList("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday");
selection.getItems().addAll(weekDays);
label.textProperty().bind(selection.selectedItemProperty());
我还建议您查看javafx.scene.control.SelectionModel
类及其子类(例如javafx.scene.control.SingleSelectionModel
)。也许,扩展其中一些可能更容易。
答案 1 :(得分:0)
我没有双向绑定,但是如果您只希望在列表中位置发生变化时更新属性,则可以使用以下代码:
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
/**
* An integer property that's bound to the index of an item in an observable list. For example, if your list
* is ["car", "train", "ship"], then new PositionInListProperty("train", list) will be 1. The binding is unidirectional.
* Changing this property doesn't affect the list.
*
* @param <T> Type of elements in the list.
*/
public class PositionInListProperty<T> extends SimpleIntegerProperty implements ListChangeListener<T> {
private final T item;
private final ObservableList<T> list;
/**
* Creates the property and binds it to an observable list.
* @param item The position of this item in the list is tracked by this property.
* @param list Whenever this list changes, the value of this property is updated.
*/
public PositionInListProperty(T item, ObservableList<T> list) {
this.item = item;
this.list = list;
this.setValue(list.indexOf(item));
list.addListener(this);
}
@Override
public void onChanged(Change<? extends T> c) {
this.setValue(list.indexOf(item));
}
它将自身添加为列表的侦听器,并对所有事件做出反应。然后,您可以照常使用属性(只读!)。 indexOf
的时间复杂度为O(n),因此,如果列表很长,则需要以某种方式对其进行优化。