现在的位置: 首页 > java > 正文
一个可以排序的jlist 转载
2012年05月05日 java ⁄ 共 7517字 暂无评论

sortJlist(点击下载例子)  http://www.blogjava.net/kissjava/archive/2008/12/20/247531.html

 

 

 

为一个JList定制一个排序,可以继承AbstractListModel,使用排序的容器如TreeSet就可以搞定,但是却失去很多灵活性,如我要原始的排列呢?
下面是一个好的处理,原文为:查看,下面是原文的一些大致介绍:

    这篇文章提供两个类,一个是 SortedListModel 继承于AbstractListModel实现排序等操作,一个SortedListModelDemo为SortedListModel测试用
 
     该SortedListModel类是一个装饰类,实行排序的所有功能。 该SortedListModelDemo类包含的应用程序演示如何使用SortedListModel 。
     那么一个ListModel的装饰类, SortedListModel类应该有如下功能:
    1、使用装饰设计模式为任何ListModel对象提供排序 
    2、 提供在排序和无序之间的映射 
    3、允许程序员为自己提供java.util.Comparator对象比较模型元素 
    4、 提供升,降,和无序排序
    5、需要最低限度的更新现有的应用程序代码
    如下图:该演示一个Jlist组件,包括一组排序类型选择的radio,和增加,删除按钮,当然你也可以整的更复杂一些。

SortedListModel

在JDK1.6中为Jtable提供了排序和筛选的功能:TableRowSorter,这个类的行为就像装饰器,为table model操作的时候排序,然而这相同的功能却没有提供给Jlist类,但是这里我们可以子创建一个SortListModel类,为ListModel提供排序功能。

因为SortedListModel对象必须包装ListModel对象,所以它至少应执行相同的接口。同时,也要支持分发数据监听事件,这里将SortedListModel继承javax.swing.AbstractListModel类,这个类可以方便的管理及通知ListDataListener对象。

SortedListModel构造函数:
通常一个装饰器通过构造函数对其传入的对象进行包装,所以SortedListModel需要传入原始的ListModel对象,以便对通过原始的model而调用一些方法。由于要进行升序,降序,以及无序的三种状态,所以传入一个排序SortOrder对象,最后还需要一个Comparator对象,来对你的Model进行怎样的排序:
代码如下:

    public SortedListModel(ListModel model, SortOrder sortOrder, Comparator comp) {
        unsortedModel = model;
        unsortedModel.addListDataListener(new ListDataListener() {
            public void intervalAdded(ListDataEvent e) {
                unsortedIntervalAdded(e);
            }
            public void intervalRemoved(ListDataEvent e) {
                unsortedIntervalRemoved(e);
            }
            public void contentsChanged(ListDataEvent e) {
                unsortedContentsChanged(e);
            }    
        });
        this.sortOrder = sortOrder;
        if (comp != null) {
            comparator = comp;
        } else {
            comparator = Collator.getInstance();
        }      
        // get base model info
        int size = model.getSize();
        sortedModel = new ArrayList<SortedListEntry>(size);
        for (int x = 0; x < size; ++x) {
            SortedListEntry entry = new SortedListEntry(x);
            int insertionPoint = findInsertionPoint(entry);
            sortedModel.add(insertionPoint, entry);
        }
    }

在上面的代码中,首先保存对原始的model,因为要它为增加、删除、改变里面的列的时候需要做出相应的反应,为原始的model添加事件监听,设置Comparator,当没有提供Comparator的时候,创建一个默认的Comparator,最后构建一个ArrayList来存入原始的model元素的索引来进行排序。

至此:这个SortedListModel对象具有如下特性:
它有一个原始model的参照。
它有用户排序方式。
它有一个Comparator对model的内容进行排序。
它有原始model的一个排序代理。

SortedListModel提供了一个SortOrder的内部类,来表示排序的方式。SortOrder是一个枚举,代码如下:

    public enum SortOrder {
        UNORDERED,
        ASCENDING,
        DESCENDING;
    }

那么原始的model和经过排序后的一种对应关系先给出图,如下:

下面是SortedListEntry类的一个比较方法,用它来对Model中的元素进行排序,SortedListModel使用java.text.Collortor来比较。她只能用来比较String,如果你的model是其他对象,那么提供自己的Comparator,如果没有的话,则SortedListModel将会调用model的元素的toString方法来进行比较。

        
        public int compareTo(Object o) {
            // retrieve the element that this entry points to
            // in the original model
            Object thisElement = unsortedModel.getElementAt(index);
            SortedListEntry thatEntry = (SortedListEntry)o;
            // retrieve the element that thatEntry points to in the original
            // model
            Object thatElement = unsortedModel.getElementAt(thatEntry.getIndex());
            if (comparator instanceof Collator) {
                thisElement = thisElement.toString();
                thatElement = thatElement.toString();
            }
            // compare the base model's elements using the provided comparator
            int comparison = comparator.compare(thisElement, thatElement);
            // convert to descending order as necessary
            if (sortOrder == SortOrder.DESCENDING) {
                comparison = -comparison;
            }
            return comparison;
        }

  

那么什么时候程序会调用这个compareTo方法呢?当你增加或改变这个排序时的model的时候,如下面这个findInsertionPoint方法使用Collections的二分查找对应的位置来插入一个元素,就会调用这个compareTo方法,代码如下:

 private int findInsertionPoint(SortedListEntry entry) {
        int insertionPoint = sortedModel.size();
        if (sortOrder != SortOrder.UNORDERED)  {
            insertionPoint = Collections.binarySearch((List)sortedModel, entry);
            if (insertionPoint < 0) {
                insertionPoint = -(insertionPoint +1);
            }
        }
        return insertionPoint;
    }

当取得一个元素的时候,不一定就是你在界面上所看到的位置,那么getElementAt方法则要做相应的处理,因为这个排序只是记录排序后的索引指,这个index要做相应的处理,如下:

    public Object getElementAt(int index) throws IndexOutOfBoundsException {
        int modelIndex = toUnsortedModelIndex(index);
        Object element = unsortedModel.getElementAt(modelIndex);
        return element;
    }

事件处理:
为原始的model添加事件监听,对数据的增加、删除,修改进行监听,如上面给出的构造函数的代码所示,注册一个ListDataListenter对象,这个匿名类包括以下几个方法,如:

        unsortedModel.addListDataListener(new ListDataListener() {
            public void intervalAdded(ListDataEvent e) {
                unsortedIntervalAdded(e);
            }
            public void intervalRemoved(ListDataEvent e) {
                unsortedIntervalRemoved(e);
            }
            public void contentsChanged(ListDataEvent e) {
                unsortedContentsChanged(e);
            }    
        });

unsortedIntervalAdded方法相对来比较复杂点,当原始未排序的model添加一个新的元素的时候,它要提供一个插入元素的开始和结束的索引,虽然这些索引在原始的model中是连续的数字,但是这些索引在已排序后的model却不上一样的,如上面的图可知,所增加一个新的元素的时候,需要进行相对应的处理,代码如下:

   private void unsortedIntervalAdded(ListDataEvent e) {
        int begin = e.getIndex0();
        int end = e.getIndex1();
        int nElementsAdded = end-begin+1;
        
        /**//* Items in the decorated model have shifted in flight.
         * Increment our model pointers into the decorated model.
         * We must increment indices that intersect with the insertion
         * point in the decorated model.
         */
        for (SortedListEntry entry: sortedModel) {
            int index = entry.getIndex();
            // if our model points to a model index >= to where
            // new model entries are added, we must bump up their index
            if (index >= begin) {
                entry.setIndex(index+nElementsAdded);
            }
        }
        
        // now add the new items from the decorated model
        for (int x = begin; x <= end; ++x) {
            SortedListEntry newEntry = new SortedListEntry(x);
            int insertionPoint = findInsertionPoint(newEntry);
            sortedModel.add(insertionPoint, newEntry);
            fireIntervalAdded(ListDataEvent.INTERVAL_ADDED, insertionPoint, insertionPoint);
        }
}

unsortedIntervalRemoved方法原理类似,这里就不给出代码,详见附件。
你的应用程序注册接受到了Jlist的事件通知的时候,如ListSelectionEvent的时候,这时候选择的元素是已经排完序的一个元素,所以要提供一个返回原始model索引的方法,要进行正确的处理,在getElementAt方法方法就调用了下面的方法,代码如下:

public int toUnsortedModelIndex(int index) throws IndexOutOfBoundsException {
        int modelIndex = -1;
        SortedListEntry entry = sortedModel.get(index);
        modelIndex = entry.getIndex();
        return modelIndex;
        
    }

  使用这个SortedListModel,只需要在你的应用程序中做一下三个步骤:

1、创建一个SortedListModel对象

2、将这个SortedListModel对象添加到Jlist组件中

3、注意排序后和未排序的model元素所对应的关系

所以在你的程序中只需要以下几句代码而已:
 

unsortedModel = new DefaultListModel();
sortedModel = new SortedListModel(unsortedModel);
list.setModel(sortedModel);

 

如上面第三条所说,有点处理得做一些额外处理,下面是一个删除方法得做出如下的一些处理:

 private void btnDeleteSelectionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeleteSelectionActionPerformed
        int[] sortedSelection = list.getSelectedIndices();
        int[] unsortedSelection = sortedModel.toUnsortedModelIndices(sortedSelection);
        
        for (int x = unsortedSelection.length - 1; x >= 0; --x) {
            unsortedModel.remove(unsortedSelection[x]);
        }
    }

给我留言

您必须 [ 登录 ] 才能发表留言!

×