JavaFx:将列表中元素的索引绑定到元素的 属性

JavaFx: Bind element's index in a list to a property of the element

我有一个 ObservableList<Model>,其中模型有一个 IntegerProperty,我想将丢失的那个元素的位置(索引)绑定到这个 IntegerProperty。因此,如果我移动该列表中的元素,我还想更改 属性。

我发现了一个类似的问题,但我不知道为什么它的答案被接受了,当答案与问题无关时...... 我说的是这个:How to bind the position in a List to an attribute of that element?

我不需要对所选项目做任何事情,只需绑定到它的 属性 列表中的 indexOf。

我尝试了这个原因,但它没有更新 id 我在列表中移动了元素:

item.indexProperty().bind(Bindings.createIntegerBinding(() -> observableList.indexOf(item), observableList));

如果您有任何其他不使用 ListChangeListener 的建议,我将不胜感激。

ListChangeListener 是一个很好的方法,因为它只需要使用一个监听器。

public static class Item {

    private final IntegerProperty index = new SimpleIntegerProperty();

    @Override
    public String toString() {
        return Integer.toString(index.get());
    }

}
ObservableList<Item> items = FXCollections.observableArrayList();
items.addListener((ListChangeListener.Change<? extends Item> c) -> {
    boolean hadNext;
    while ((hadNext = c.next()) && c.wasPermutated()) {
        int to = c.getTo();
        for (int i = c.getFrom(); i < to; i++) {
            items.get(i).index.set(i);
        }
    }

    while (hadNext) {
        if (c.wasReplaced()) {
            int to = c.getTo();
            for (int i = c.getFrom(); i < to; i++) {
                items.get(i).index.set(i);
            }
        } else {
            if (!c.wasUpdated()) {
                // add/remove change
                int to = items.size();
                for (int i = c.getFrom(); i < to; i++) {
                    items.get(i).index.set(i);
                }
            }
            break;
        }
        hadNext = c.next();
    }

});

或者您可以使用 FXCollections.observableList 并让后备列表处理此问题:

private static class ItemsList extends AbstractList<Item> {

    private final List<Item> data = new ArrayList<>();

    @Override
    public Item get(int index) {
        return data.get(index);
    }

    @Override
    public int size() {
        return data.size();
    }

    private void updateFromIndex(int index) {
        int size = size();

        for (; index < size; index++) {
            data.get(index).index.set(index);
        }
    }

    @Override
    public Item remove(int index) {
        Item result = data.remove(index);
        updateFromIndex(index);
        return result;
    }

    @Override
    public void add(int index, Item element) {
        data.add(index, element);
        updateFromIndex(index);
    }

    @Override
    public Item set(int index, Item element) {
        element.index.set(index);
        return data.set(index, element);
    }

}
ObservableList<Item> items = FXCollections.observableList(new ItemsList());

请注意,可以针对后备列表对执行多个 insertions/deletions 的处理操作进行优化。


在这两种情况下

for (int i = 0; i < 5; i++) {
    System.out.println(items);
    items.add(new Item());
}
System.out.println(items);
Collections.swap(items, 0, 4);
System.out.println(items);
Collections.swap(items, 2, 3);
System.out.println(items);
Collections.swap(items, 0, 2);
System.out.println(items);

产生以下控制台打印输出:

[]
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4]

"A simple more readable solution" 可以是

items.addListener((ListChangeListener.Change<? extends Model> c) -> {
    int i=0;
    for (Model model : c.getList()) {
        model.setIndex(i++);
    }
})

它首先初始化所有属性 add 并保持所有属性更新。
注意 fabian 的评论:

you may do more work than necessary

.