【问题标题】:JavaFx: Bind element's index in a list to a property of the elementJavaFx:将列表中元素的索引绑定到元素的属性
【发布时间】:2018-11-24 01:22:21
【问题描述】:

我有一个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 的情况下有任何其他建议,我将不胜感激。

【问题讨论】:

  • 我觉得很奇怪Bindings.createIntegerBinding(...) 不适合你。我只是尝试了同样的事情,IntegerProperty 已正确更新。虽然 fabian 提供的选项会更有效率。

标签: java javafx binding javafx-8


【解决方案1】:

“一个简单易读的解决方案”可能是

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

它在第一个add 上初始化所有属性并保持所有属性更新。
注意fabian的评论:

你可能会做比需要更多的工作

.

【讨论】:

    【解决方案2】:

    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());
    

    请注意,可以对支持列表进行多次插入/删除操作的处理进行了优化。


    在这两种情况下

    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]
    

    【讨论】:

    • 那么您会推荐ListChangeListener 解决方案吗?
    • 是的。或者有什么理由不使用这种方法?这样您就可以确保最多更新每个项目两次(一次用于排列,一次用于添加/替换)...
    • 不,或者不是一个重要的原因,我只是觉得有一个比监听器方法更简单易读的解决方案。
    • 是否可以使用items.addListener((ListChangeListener.Change&lt;? extends Model&gt; c) -&gt; { int i=0; for (Model model : c.getList()) { model.setIndex(i++); } }); 更新每次更改时的所有属性
    • @c0der 这是可能的,但你可能做的工作比必要的多。例如考虑替换单个元素或从列表末尾添加/删除...
    猜你喜欢
    • 1970-01-01
    • 2014-12-04
    • 2018-10-28
    • 2018-06-04
    • 2017-02-26
    • 2018-10-21
    • 2013-05-31
    • 2011-08-09
    • 1970-01-01
    相关资源
    最近更新 更多