如何将List中的位置绑定到该元素的属性?

时间:2013-04-25 14:42:04

标签: java javafx-2 bind observablelist

我有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属性自动更新

这可能吗?我可以在这些值之间建立双向绑定吗?

2 个答案:

答案 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),因此,如果列表很长,则需要以某种方式对其进行优化。