3

我有一个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 中拖放或其他任何东西),我希望位置属性能够自动更新。

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

4

2 回答 2

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)。也许,扩展其中一些可能更容易。

于 2013-08-02T13:20:53.597 回答
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),所以如果你有一个很长的列表,你会想以某种方式优化它。

于 2019-03-31T08:37:25.247 回答