有才華的人,別忘記給滋潤你的那塊土壤施肥

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            28 隨筆 :: 5 文章 :: 147 評論 :: 0 Trackbacks
               為一個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]);
                  }

              }


          PS:原文提供的代碼的測試代碼的布局用了一些Jdesktop類的引用,我做了一些改變,需要的朋友可以在這里下載 
          posted on 2008-12-20 18:52 kissjava 閱讀(4208) 評論(3)  編輯  收藏 所屬分類: swing

          評論

          # re: 一個可排序的JList 2008-12-26 22:40 Qil.Wong
          換我實現,不會搞這么復雜,直接使用Collections.sort(list),最后更新model就行  回復  更多評論
            

          # re: 一個可排序的JList 2008-12-27 15:22 枯寬
          @Qil.Wong
          正如開篇所說的第五條:需要最低限度的更新現有的應用程序代碼
            回復  更多評論
            

          # re: 一個可排序的JList 2010-05-12 13:33 師大
          @Qil.Wong
          要是我的話也這樣。  回復  更多評論
            

          主站蜘蛛池模板: 固原市| 四会市| 社会| 台湾省| 河东区| 秭归县| 双柏县| 石柱| 云南省| 离岛区| 吴旗县| 祁连县| 富民县| 佳木斯市| 柏乡县| 鱼台县| 巴里| 集安市| 岗巴县| 南召县| 南和县| 石首市| 华宁县| 五台县| 当涂县| 聂拉木县| 新闻| 延寿县| 弋阳县| 余干县| 双峰县| 荔浦县| 普兰县| 麻江县| 琼结县| 古丈县| 渑池县| 仙居县| 深州市| 曲水县| 堆龙德庆县|