java - 如何使我的 ImmutableList 在其 ObservableList 包装器中可排序?

标签 java javafx javafx-8 guava

我有自己的 ObservableList 实现,称为 ObservableImmutableList。它用 ObservableList 接口(interface)包装了一个 Guava ImmutableList,因此我可以通过 JavaFX 轻松地充分利用 ImmutableList。除了它允许使用 set() 方法将另一个 ImmutableList 交换为后备列表(并通知所有监听器/绑定(bind)更改)之外,它没有任何可变性.

然而,one problem I ran into is the ObservableImmutableList cannot be sorted.我无法扩展或实现 SortedList,那么如何将它实现到此类中呢?

我尝试创建一个方法 asSorted(),它返回包装在 SortedList 中的 ObservableImmutableList。但它也行不通。是否可以使用某种简单的抽象层来保持列表不可变但允许在抽象层中对值进行排序?

public final class ObservableImmutableList<T> implements ObservableList<T> {
    private volatile ImmutableList<T> backingList;
    private final LazyProperty<SortedList<T>> sortedList = LazyProperty.forSupplier(() -> new SortedList<>(this));
    private final CopyOnWriteArrayList<ListChangeListener<? super T>> listeners = new CopyOnWriteArrayList<>();
    private final CopyOnWriteArrayList<InvalidationListener> invalidationListeners = new CopyOnWriteArrayList<>();

    private final ObjectProperty<ObservableList<T>> property;

    private ObservableImmutableList(ImmutableList<T> immutableList) {
        this.backingList = immutableList;
        this.property = new SimpleObjectProperty<ObservableList<T>>(this);
    }

    public static <T> ObservableImmutableList<T> of(ImmutableList<T> immutableList) {
        return new ObservableImmutableList<T>(immutableList);
    }
    public SortedList<T> asSorted() { 
        return sortedList.get();
    }
    public void set(ImmutableList<T> immutableList) { 

        this.property.setValue(this);

        final ImmutableList<T> oldList = this.backingList;
        final ImmutableList<T> newList = immutableList;
        listeners.forEach(l -> l.onChanged(new Change<T>(this) {
            private int changeNum = 0;
            @Override
            public boolean next() {
                changeNum++;
                return changeNum <= 2 ? true : false;
            }
            @Override
            public boolean wasUpdated() {
                return true;
            }
            @Override
            public void reset() {
                // TODO Auto-generated method stub

            }
            @Override
            public int getFrom() {
                return 0;
            }
            @Override
            public int getTo() {
                return changeNum == 1 ? oldList.size() - 1 : newList.size() - 1;
            }
            @Override
            public List<T> getRemoved() {
                return changeNum == 1 ? oldList : ImmutableList.of();
            }
            @Override
            public List<T> getAddedSubList() { 
                return changeNum == 1 ? ImmutableList.of() : newList;
            }
            @Override
            protected int[] getPermutation() {
                int[] permutations = new int[changeNum == 1 ? oldList.size() : newList.size()];
                for (int i = 0; i < permutations.length; i++) { 
                    permutations[i] = i;
                }
                return permutations;
            }

        }));
        this.backingList = immutableList;

        invalidationListeners.forEach(l -> l.invalidated(this));

    }

    public ImmutableList<T> get() { 
        return backingList;
    }
    public ObjectProperty<ObservableList<T>> asProperty() { 
        return property;
    }

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

    @Override
    public boolean isEmpty() {
        return backingList.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return backingList.contains(o);
    }

    @Override
    public Iterator<T> iterator() {
        return backingList.iterator();
    }

    @Override
    public Object[] toArray() {
        return backingList.toArray();
    }

    @Override
    public <B> B[] toArray(B[] a) {
        return backingList.toArray(a);
    }

    @Override @Deprecated
    public boolean add(T e) {
        return backingList.add(e);
    }

    @Override @Deprecated
    public boolean remove(Object o) {
        return backingList.remove(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return backingList.containsAll(c);
    }

    @Override @Deprecated
    public boolean addAll(Collection<? extends T> c) {
        return backingList.addAll(c);
    }

    @Override @Deprecated
    public boolean addAll(int index, Collection<? extends T> c) {
        return backingList.addAll(index, c);
    }

    @Override @Deprecated
    public boolean removeAll(Collection<?> c) {
        return backingList.removeAll(c);
    }

    @Override @Deprecated
    public boolean retainAll(Collection<?> c) {
        return backingList.retainAll(c);
    }

    @Override @Deprecated
    public void clear() {
        backingList.clear();
    }

    @Override
    public T get(int index) {
        return backingList.get(index);
    }

    @Override @Deprecated
    public T set(int index, T element) {
        return backingList.set(index, element);
    }

    @Override @Deprecated
    public void add(int index, T element) {
        backingList.add(index, element);
    }

    @Override @Deprecated
    public T remove(int index) {
        return backingList.remove(index);
    }

    @Override
    public int indexOf(Object o) {
        return backingList.indexOf(o);
    }

    @Override
    public int lastIndexOf(Object o) {
        return backingList.lastIndexOf(o);
    }

    @Override
    public ListIterator<T> listIterator() {
        return backingList.listIterator();
    }

    @Override
    public ListIterator<T> listIterator(int index) {
        return backingList.listIterator(index);
    }

    @Override
    public ImmutableList<T> subList(int fromIndex, int toIndex) {
        return backingList.subList(fromIndex, toIndex);
    }

    @Override
    public void addListener(InvalidationListener listener) {
        invalidationListeners.add(listener);
    }

    @Override
    public void removeListener(InvalidationListener listener) {
        invalidationListeners.remove(listener);
    }

    @Override
    public void addListener(ListChangeListener<? super T> listener) {
        listeners.add(listener);
    }

    @Override
    public void removeListener(ListChangeListener<? super T> listener) {
        listeners.remove(listener);
    }

    @Override @Deprecated
    public boolean addAll(T... elements) {
        return backingList.addAll(ImmutableList.copyOf(elements));
    }

    @Override @Deprecated
    public boolean setAll(T... elements) {
        return false;
    }

    @Override @Deprecated
    public boolean setAll(Collection<? extends T> col) {
        return false;
    }

    @Override @Deprecated
    public boolean removeAll(T... elements) {
        return backingList.removeAll(ImmutableList.copyOf(elements));
    }

    @Override @Deprecated
    public boolean retainAll(T... elements) {
        return false;
    }

    @Override @Deprecated
    public void remove(int from, int to) {
    }

    @Override
    public String toString() { 
        return backingList.toString();
    }

}

最佳答案

您询问的部分:SortedList 只是其支持列表的包装器,它不会以任何方式更改它。因此,您可以将任何列表(可变或不可变)包装到一个 SortedList 中,并在 TableView 中使用它。在您上一个问题的示例中:

ObservableList<NumericCombo> immutable = 
        FXCollections.unmodifiableObservableList(values);
 //       new ImmutableObservableList<>(values);

TableView<NumericCombo> tableView = new TableView<>();
SortedList sorted = new SortedList(immutable);
tableView.setItems(sorted);
sorted.comparatorProperty().bind(tableView.comparatorProperty());

您没有询问的部分(如何获得正确的通知)。

  • 不要从头开始实现 ObservableList,而是从 ObservableListBase 开始
  • 当换出backing list时,调用super提供的support方法通知listeners

一个简单的例子:

public class ImmutableObservableList<E> extends ObservableListBase<E> {

    private List<E> backing;

    public ImmutableObservableList(List<E> backingList) {
        this.backing = backingList;
    }

    public void setBackingList(List<E> backingList) {
        beginChange();
        if (this.backing != null) {
            nextRemove(0, this.backing);
        }
        this.backing = backingList;
        if (backingList != null) {
            nextAdd(0, backingList.size());
        }
        endChange();
    }
    @Override
    public E get(int index) {
        if (backing == null) throw new IndexOutOfBoundsException();
        return backing.get(index);
    }

    @Override
    public int size() {
        return backing != null ? backing.size() : 0;
    }

}

关于java - 如何使我的 ImmutableList 在其 ObservableList 包装器中可排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29630944/

相关文章:

java - 如何在gradle assemble中包含javafx项目的CSS文件?

java - 如何在javafx中打印表格

java - Javafx 的新阶段即将到来

javafx-2 - 图标悬停效果

installation - 带有 Inno Setup 5 的 JavaFX 自安装程序 - 允许用户更改安装目录

java - 关闭 hibernate 日志控制台输出

java - 如果在 JTable 中选择

javascript - 在 JavaFX 中访问 Javascript 的返回值

java - 将 Erlang UTF-8 编码的字符串转换为 java.lang.String

java - 使用 JDBC 与 MySQL、JAVA REST 和 Python REST 进行序列化