如何通过操纵ObservableList引起排列事件?

时间:2016-08-12 09:48:14

标签: java javafx observablelist

ObservableList听众可以通过置换集接收Change个事件。

同时,在列表操作中,我只看到要删除或插入元素的那些。

是否可以在列表上执行此类操作,这将导致报告排列?

更新

以下是澄清代码:

public class ObservableListPermutation {

   public static void main(String[] args) {

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


      list.add("timbuktu");
      list.add("timid");

      list.addListener(new ListChangeListener<String>() {
         @Override
         public void onChanged(Change<? extends String> c) {
            while(c.next()) {
               if( c.wasPermutated() ) {
                  System.out.println("Was permutated");
               }
            }
         }
      });

      System.out.println("Sorting by library:");
      Collections.sort(list);

      System.out.println("Sorting by own:");
      Collections2.sort(list);


   }


   public static class Collections2 {
      public static void sort(List<String> list) {
         String element = list.remove(0);
         list.add(element);
      }
   }
}

如您所见,我的自定义排列不会导致排列事件,因为它是通过删除和添加元素来完成的。如何实现自定义排列,以便导致排列事件?

更新2

如果我尝试使用调试器跟踪sort(),我将无法输入sort()的代码。

2 个答案:

答案 0 :(得分:2)

一个非常简单的操作,List to report Permutation将对List中的项进行排序。

例如,以下代码将打印true

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

import java.util.Collections;

public class PermutationTest {

    public static void main(String[] args) {

        ObservableList<String> list = 
                         FXCollections.observableArrayList("Z", "Y", "X");
        list.addListener(new ListChangeListener<String>() {
            @Override
            public void onChanged(Change<? extends String> c) {
                c.next();
                System.out.println(c.wasPermutated());
            }
        });
        Collections.sort(list);
    }
}

其他问题的答案:

  

我想自己做,不用黑盒子方法。假设我有ObservableList的实例,仅此而且想编写一些操作,这会导致排列,我该怎么做?

如果您使用FXCollections util类提供的 ObservableList,则无法实现,因为ObservableList的实现方式。

考虑以下几点:

现在,您一定想知道(就像我一样),当我们在同一个列表上进行排序时,它是如何工作的?

事实证明ObservableListWrapper(这是在FXCollections中创建列表的基础)会覆盖sort(),然后强制SimplePermutationChange

  

有替代方案吗?

您可以按照ModifiableObservableListBase所述并this comment中显示的this answer扩展来创建您自己的自定义ObservableList。

答案 1 :(得分:1)

详细说明@ ItachiUchiha的回答和@ fabian的评论,修改ObservableList的任何单个操作都将通知更改侦听器。因此,无法通过调用每个修改列表的操作序列来触发ObservableList上的“置换事件”(每个操作都会独立地通知侦听器)。

因此,为了支持开箱即用(即FXCollections.sort()FXCollections.shuffle()FXCollections.rotate()FXCollections.reverse())不支持的排列,您需要实现自己的排列ObservableList,定义(或可能覆盖)触发排列的单个入口点方法。 ModifiableObservableListBase class提供了一个方便的起点。

这是一个简单的例子:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import javafx.collections.ModifiableObservableListBase;

public class PermutatingObservableList<E> extends ModifiableObservableListBase<E> {


    private final List<E> source ;

    public PermutatingObservableList(List<E> source) {
        this.source = source ;
    }

    public void permute(int[] permutation) {
        checkPermutation(permutation);
        beginChange();
        List<E> temp = new ArrayList<>(source);
        for (int i = 0 ; i < size() ; i++) {
            source.set(i, temp.get(permutation[i]));
        }
        nextPermutation(0, size(), permutation);
        endChange();
    }

    public void pairwiseSwap() {
        int[] permutation = new int[size()];
        for (int i = 0; i+1 < permutation.length ; i+=2) {
            permutation[i] = i+1 ;
            permutation[i+1] = i ;
        }
        if (permutation.length % 2 == 1) {
            permutation[permutation.length - 1] = permutation.length - 1 ;
        }
        permute(permutation);
    }

    private void checkPermutation(int[] permutation) {
        boolean valid = permutation.length == size();
        Set<Integer> values = IntStream.range(0, size()).boxed().collect(Collectors.toSet());
        for (int i=0; i<permutation.length && valid ; i++) {
            valid = values.remove(new Integer(permutation[i]));
        }
        if (! valid) {
            throw new IllegalArgumentException("Invalid permuation: "+Arrays.toString(permutation)+"\n"
                    +"Permutation must be same length as list and must contain each of the values "
                    + "0-"+(size()-1)+" exactly once");
        }
    }

    @Override
    public E get(int index) {
        return source.get(index);
    }

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

    @Override
    protected void doAdd(int index, E element) {
        source.add(index, element);
    }

    @Override
    protected E doSet(int index, E element) {
        return source.set(index, element);
    }

    @Override
    protected E doRemove(int index) {
        return source.remove(index);
    }

}

和测试:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import javafx.collections.ListChangeListener;

public class PermutingObservableListTest {

    public static void main(String[] args) {
        List<String> numbers = Arrays.asList("One", "Two", "Three", "Four", "Five");
        PermutatingObservableList<String> list = new PermutatingObservableList<>(new ArrayList<>(numbers));
        list.addListener(new ListChangeListener<String>() {
            @Override
            public void onChanged(Change<? extends String> c) {
                while (c.next())
                    System.out.println(c.wasPermutated());
                    System.out.println(IntStream.range(0, list.size())
                        .map(c::getPermutation)
                        .mapToObj(Integer::toString)
                        .collect(Collectors.joining(", ")));
                }
            }
        });

        list.pairwiseSwap();

        System.out.println(list);
    }
}

产生输出

true
1, 0, 3, 2, 4
[Two, One, Four, Three, Five]