ObservableList 绑定内容与元素转换

sdo*_*rof 7 binding javafx observablelist

有没有一种方法可以通过它们之间的元素转换来绑定两个可观察列表的内容?例如,这样的事情:

ObservableList<Model> models = FXCollections.observableArrayList();
ObservableList<TreeItem<Model>> treeItemModels = FXCollections.observableArrayList();
Bindings.bindContent(treeItemModels, models, m -> new TreeItem<Model>(m));
Run Code Online (Sandbox Code Playgroud)

sdo*_*rof 9

正如James_D所说,这个功能在标准 API 中是不存在的,可以使用 ReactFX 框架来实现。但是,如果多余的依赖项不是选项,那么没有它们也可以轻松实现此类功能。为此,通过必要的修改Bindings#bindContentContentBinding#bind查看 to的 JDK 源代码ListContentBinding并进行复制/粘贴就足够了。结果我们得到了一个像标准内容绑定一样工作的绑定:

ObservableList<Model> models = FXCollections.observableArrayList();
ObservableList<TreeItem<Model>> treeItemModels = FXCollections.observableArrayList();
BindingUtil.mapContent(treeItemModels, models, m -> new TreeItem<Model>(m));
Run Code Online (Sandbox Code Playgroud)

这个的来源BindingUtil

public class BindingUtil {

    public static <E, F> void mapContent(ObservableList<F> mapped, ObservableList<? extends E> source,
            Function<? super E, ? extends F> mapper) {
        map(mapped, source, mapper);
    }

    private static <E, F> Object map(ObservableList<F> mapped, ObservableList<? extends E> source,
            Function<? super E, ? extends F> mapper) {
        final ListContentMapping<E, F> contentMapping = new ListContentMapping<E, F>(mapped, mapper);
        mapped.setAll(source.stream().map(mapper).collect(toList()));
        source.removeListener(contentMapping);
        source.addListener(contentMapping);
        return contentMapping;
    }

    private static class ListContentMapping<E, F> implements ListChangeListener<E>, WeakListener {
        private final WeakReference<List<F>> mappedRef;
        private final Function<? super E, ? extends F> mapper;

        public ListContentMapping(List<F> mapped, Function<? super E, ? extends F> mapper) {
            this.mappedRef = new WeakReference<List<F>>(mapped);
            this.mapper = mapper;
        }

        @Override
        public void onChanged(Change<? extends E> change) {
            final List<F> mapped = mappedRef.get();
            if (mapped == null) {
                change.getList().removeListener(this);
            } else {
                while (change.next()) {
                    if (change.wasPermutated()) {
                        mapped.subList(change.getFrom(), change.getTo()).clear();
                        mapped.addAll(change.getFrom(), change.getList().subList(change.getFrom(), change.getTo())
                                .stream().map(mapper).collect(toList()));
                    } else {
                        if (change.wasRemoved()) {
                            mapped.subList(change.getFrom(), change.getFrom() + change.getRemovedSize()).clear();
                        }
                        if (change.wasAdded()) {
                            mapped.addAll(change.getFrom(), change.getAddedSubList()
                                    .stream().map(mapper).collect(toList()));
                        }
                    }
                }
            }
        }

        @Override
        public boolean wasGarbageCollected() {
            return mappedRef.get() == null;
        }

        @Override
        public int hashCode() {
            final List<F> list = mappedRef.get();
            return (list == null) ? 0 : list.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }

            final List<F> mapped1 = mappedRef.get();
            if (mapped1 == null) {
                return false;
            }

            if (obj instanceof ListContentMapping) {
                final ListContentMapping<?, ?> other = (ListContentMapping<?, ?>) obj;
                final List<?> mapped2 = other.mappedRef.get();
                return mapped1 == mapped2;
            }
            return false;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的解决方案,我只需将 3 次出现的 `toList()` 更改为 `Collectors.toList()` 即可编译。 (2认同)