技术开发 频道

Swing 模型过滤

  替换过滤的目的在于,重新解释模型数据,并且通过改变返回的对象元素来表示它。这种类型的过滤器不改变数据元素的顺序,它既不删除数据,也不创建额外的数据。

  下面是一个替换过滤器的示例,它为底层模型中的每个数据项添加一个数字索引。唯一的变化是覆盖了单个方法。

  替换过滤器的示例

1 package com.ketherware.models;
2 import javax.swing.*;
3 public abstract class IndexingListModelFilter extends AbstractListModelFilter
4 {
5 public Object getElementAt(int index)
6     {
7     // 委托给过滤器目标
8     String element = delegate.getElementAt(index).toString();
9     return Integer.toString(index) + ? ?+ element;
10     }
11 }
12

  在许多情况下,在绘制程序中引入补充的特性可能更合适,比如填加一个行索引。您可以提供一个过滤器,它通过与绘制程序交互来提供额外的图形表示。使用过滤器代替绘制程序的优点在于,可用一个组件显示经过索引的数据,而无须与绘制程序相关联。

  替换过滤器通常不覆盖 getSize() ,而且不改变所返回元素的顺序。

  排序过滤器

  排序过滤器代表了另一层面的复杂性。它们不改变所表示元素的个数,在这一点上与替换过滤器类似。排序过滤器改变模型中经过索引的元素顺序。其基本技术在于,创建模型元素的一种替代索引,用于代替实际的顺序。

  排序过滤器的一种常见类型是分类过滤器,它基于某个明确的排序顺序重新索引数据。下面的示例按字母顺序排列任一个 ListModel 实现的内容。

  排序过滤器的示例

1 package com.ketherware.models;
2 import java.util.*;
3 import javax.swing.*;
4 public abstract class AlphaSortingListModelFilter extends
5                     AbstractListModel
6 {
7 // 已排序的索引数组
8 protected ArrayList sortedIndex;
9 public AlphaSortingListModelFilter(ListModel delegate)
10     {
11     this.delegate = delegate;
12     resort();
13     }
14 // 该算法称为“插入排序”,适合于处理元素个数少于几百个的数据。
15 // 它是一种“无堆栈”排序。
16 protected synchronized void resort()
17     {
18     sortedIndex = new ArrayList();
19     nextElement:
20     for (int x=0; x < delegate.getSize(); x++)
21         {
22             for (int y=0; y < x; y++)
23             {
24                 String current =
25                     delegate.getElementAt(x).toString();
26                 int compareIndex =
27                     ((Integer) sortedIndex.get(y)).intValue();
28                 String compare =
29                     sortedIndex.get(compareIndex).toString();
30                 if (current.compareTo(compare) < 0)
31                 {
32                     sortedList.add(new Integer(x), y);
33                     continue nextElement;
34                 }
35             }
36             sortedList.add(new Integer(x));
37         }
38     }
39     public Object getElementAt(int index)
40     {
41         // 委托给过滤器目标,但使用已排序的索引
42         return delegate.getElementAt(sortedIndex[index]);
43     }
44 }
45

  可以将一种排序过滤器用于 JTable 组件,以便对表数据执行面向列的排序;这种过滤器的代码类似于上面的示例。通过修改 JTable 的表头和表的模型组件,该过滤器可以得到进一步的增强。

  请注意,上面的示例只对不可变列表模型有效。如果数据在动态变化,为了修改在事件被触发时由 ListDataEvent 对象传递的索引,必须提供一些附加支持。这将显著增加过滤器的复杂性,我将它的实现作为一个练习留给读者。

  排序过滤器的主要特征在于,他们不增加或者减少模型的可见元素个数,因此, getSize() 将委托给被过滤的模型。他们通常将不改变数据元素,而只是按照某种替代顺序解释数据的索引。

  排除过滤器

  最后两种类型的过滤器非常相似,但是,拥有完全不同的目的。排除过滤器与包含过滤器都允许对模型的数据元素进行限制或者补充额外的元素。

  排除过滤器使模型中的某些元素看似不存在。在只有单一数据源可用、并且实现方案只要求显示数据的一个子集的情况下,这些过滤器相当有效。

  关于典型的排除过滤器的示例,请参考 TerritoryListModelFilter.java。该示例给出了一个销售区域列表,其中每个区域都与一个销售人员相关联。当选定一个销售人员的姓名时,过滤器只显示与该销售人员相关联的那些区域。

  这个示例的优点非常明显:如果不进行过滤,则每次选定一个不同的销售人员都需要重新加载数据模型,或者在高速缓存中保存大量的模型实例。过滤器甚至允许两个不同的组件用两种不同的解释方案查看同一个基本模型。

  包含过滤器

  包含过滤器尽管不像排除过滤器那样广泛适用,但它们可用来向模型中添加信息。由于这种类型的过滤器可用于进行总计或者小计,这些过滤器的非常好的用途是报表应用程序。

  执行总计操作的过滤器创建一个虚拟元素,并将其显示在列表模型的尾部。为了实现这一功能,过滤器将模型大小的值加 1,并将对除最后一个元素之外的所有元素的请求发送至代理。 SalesTotalListModelFilter.java 中的示例假定列表数据是不可变的;过滤器将列表数据事件忽略。这里再一次用到前一个示例中的 TerritoryListModel。

        

  小结

  这些示例已经显示了模型过滤的某些应用。过滤是一种应用相当广泛的概念,远远不止本文这些相对比较简单的应用。当您开始实现过滤器时,请记住下列几点:

  过滤可以向不同组件提供不同的视图,并且可以减少应用程序必须支持的完整模型实例的个数。

  过滤可以应用于 Swing 支持的其他模型,包括选择模型。

  您可以为处理可变模型或者动态模型构造非常复杂的过滤方案。为了实现这一点,可以用一个过滤器来处理由该代理模型传递的事件。

  您可以无限地嵌套(或叠用)过滤器,但是,当每次修改或者查询模型时,每个过滤层都会增加一些额外的处理负担。

0
相关文章