将ObservableList绑定到另外两个ObservableLists的内容?

时间:2014-12-25 06:47:48

标签: javafx javafx-8

如果我有两个单独的ObservableLists,并且两个都放在一个ObservableList中用于TableView ...有没有办法在这两个ObservableLists和聚合的ObservableLists之间创建绑定?我试图乱用并覆盖ObjectBinding的calculate()方法,但我不认为这是我想要的。关于如何解决这个问题的任何想法?

更新:继续相关切线以显示下面讨论的含义。这是我的ObservableImmutableList实现,它正在努力使用已检查的解决方案。

   package com.nield.utilities.fx;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.CopyOnWriteArrayList;

import javafx.beans.InvalidationListener;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;

import com.google.common.collect.ImmutableList;


public final class ObservableImmutableList<T> implements ObservableList<T> {
    private volatile ImmutableList<T> backingList;
    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 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();
    }

}

到目前为止,这是将两个ObservableLists合并在一起的静态工厂。它适用于ObservableList的标准实现,但它不能与我的ObservableImmutableList实现一起使用。

package com.nield.finance;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import com.google.common.collect.ImmutableList;
import com.nield.utilities.fx.ObservableImmutableList;

public class ObservableMerge {
    static ObservableImmutableList<String> a = ObservableImmutableList.of(ImmutableList.of("ABQ","DAL"));
    static ObservableImmutableList<String> b = ObservableImmutableList.of(ImmutableList.of("HOU","PHX"));

    static ObservableList<String> aandb = FXCollections.observableArrayList();


    static ObservableList<String> merge(ObservableList<String> into, ObservableList<String>... lists) {
        final ObservableList<String> list = into;
        for (ObservableList<String> l : lists) {
            list.addAll(l);
            l.addListener((javafx.collections.ListChangeListener.Change<? extends String> c) -> {
                while (c.next()) {
                    if (c.wasAdded()) {
                        list.addAll(c.getAddedSubList());
                    }
                    if (c.wasRemoved()) {
                        list.removeAll(c.getRemoved());
                    }
                    if (c.wasUpdated()) {
                        list.removeAll(c.getRemoved());
                        list.addAll(c.getAddedSubList());
                    }
                }
            });
        }

        return list;
    }
    public static void main(String...args) {
        merge(aandb, a, b);

        System.out.println(""+aandb);
        a.set(ImmutableList.of("LAX", "BUR"));
        System.out.println(""+aandb);

    }
}

And here is the static factory to merge two ObservableLists (it should work with the ObservableImmutableList too, but its not.


package com.nield.finance;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import com.google.common.collect.ImmutableList;
import com.nield.utilities.fx.ObservableImmutableList;

public class ObservableMerge {
    static ObservableImmutableList<String> a = ObservableImmutableList.of(ImmutableList.of("ABQ","DAL"));
    static ObservableImmutableList<String> b = ObservableImmutableList.of(ImmutableList.of("HOU","PHX"));

    static ObservableList<String> aandb = FXCollections.observableArrayList();


    static ObservableList<String> merge(ObservableList<String> into, ObservableList<String>... lists) {
        final ObservableList<String> list = into;
        for (ObservableList<String> l : lists) {
            list.addAll(l);
            l.addListener((javafx.collections.ListChangeListener.Change<? extends String> c) -> {
                while (c.next()) {
                    if (c.wasAdded()) {
                        list.addAll(c.getAddedSubList());
                    }
                    if (c.wasRemoved()) {
                        list.removeAll(c.getRemoved());
                    }
                    if (c.wasUpdated()) {
                        list.removeAll(c.getRemoved());
                        list.addAll(c.getAddedSubList());
                    }
                }
            });
        }

        return list;
    }
    public static void main(String...args) {
        merge(aandb, a, b);

        System.out.println(""+aandb);
        a.set(ImmutableList.of("LAX", "BUR"));
        System.out.println(""+aandb);

    }
}

2 个答案:

答案 0 :(得分:5)

这可能是一个起点:

    public class ObservableMerge {
        static ObservableList<String> a = FXCollections.observableArrayList();
        static ObservableList<String> b = FXCollections.observableArrayList();

        static ObservableList<String> aandb = FXCollections.observableArrayList();


        static ObservableList<String> merge(ObservableList<String> into, ObservableList<String>... lists) {
            final ObservableList<String> list = into;
            for (ObservableList<String> l : lists) {
                list.addAll(l);
                l.addListener((javafx.collections.ListChangeListener.Change<? extends String> c) -> {
                    while (c.next()) {
                        if (c.wasAdded()) {
                            list.addAll(c.getAddedSubList());
                        }
                        if (c.wasRemoved()) {
                            list.removeAll(c.getRemoved());
                        }
                    }
                });
            }

            return list;
        }
        public static void main(String...args) {
            merge(aandb, a, b);

            System.out.println(""+aandb);
            a.add("Hello");
            b.add("Peter");
            System.out.println(""+aandb);

        }
    }

答案 1 :(得分:1)

以为我会为未来的读者记录这个。 RxJavaFX使这样的推动驱动任务变得更容易。

    ObservableList<String> list1 = FXCollections.observableArrayList();
    ObservableList<String> list2 = FXCollections.observableArrayList();

    ObservableList<String> combinedList = FXCollections.observableArrayList();

    Observable.combineLatest(
                JavaFxObservable.fromObservableList(list1),
                JavaFxObservable.fromObservableList(list2),
            (l1,l2) -> {
                ArrayList<String> combined = new ArrayList<>();
                combined.addAll(l1);
                combined.addAll(l2);
                return combined;
            }).subscribe(combinedList::setAll);

//return unmodifiable version of combinedList

这是一个完整的工作示例:

    ObservableList<String> list1 = FXCollections.observableArrayList();
    ObservableList<String> list2 = FXCollections.observableArrayList();

    ObservableList<String> combinedList = FXCollections.observableArrayList();

    Observable.combineLatest(
                JavaFxObservable.fromObservableList(list1),
                JavaFxObservable.fromObservableList(list2),
            (l1,l2) -> {
                ArrayList<String> combined = new ArrayList<>();
                combined.addAll(l1);
                combined.addAll(l2);
                return combined;
            }).subscribe(combinedList::setAll);

    JavaFxObservable.fromObservableList(combinedList).subscribe(System.out::println);

    list1.add("Alpha");
    list2.add("Beta");
    list1.add("Gamma");
    list1.remove("Alpha");
    list2.add("Delta");

    Thread.sleep(10000);

输出

[]
[Alpha]
[Alpha, Beta]
[Alpha, Gamma, Beta]
[Gamma, Beta]
[Gamma, Beta, Delta]