本文主要是介绍具有可过滤功能的JList组件【Swing】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
【场景】:在一个列表中,可以通过输入某个字符,而动态过滤列表中项的显示。当然,动态显示的项都是包含用户输入的字符!在此,实现的功能非常简单,没有 更多的复杂逻辑。仅是为学习者提供一些案例。可以从中进行自己需要的扩展。
【关系图】:

在Swing中,想构建自己的组件,最简单的就是继承现有的组件,再做可定制的功能扩展,也不需要做太多额外的工作,因为Swing为我们提供了良好的可 扩展性。上图,简略的说明了待开发的可过滤的列表关系类图。以下做一些简单的描述:
【FilteredList】:继承了JList,其中类FilteredModel与FilteredTextField是他的内部类实现。在这里使用 内部类是为了能够方便的访问到FilteredList外部数据,减少了与外部类的交互,在此不能确定的说这种方式是好是坏,其中的衡量就留给用户了。
【FilteredModel】:继承了AbstractListModel,FilteredList中的内部类,并作为其的一个属性存在。作用是保存 展现在列表中的数据,并且能做动态更新。
【FilteredTextField】:继承了JTextFiled,很显然的就是一个输入框,只是实现了一个DocumentListener接口, 做到实时监听用户输入的任何动作:插入、删除、修改等。在用户触发这个监听时,就需要和FilteredModel进行交互,动态变化 FilteredList中的数据显示。
【编码实现】
FilteredModel :
在这个Model中主要的是设置一个filteredItems 属性,用来保存包含了用户输入字符的列表项;另一个items属性,保存列表原始的所有项。关键的算法是方法refilter():实时对用户输入进行过 滤,并把结果添加到filteredItems 中。
private class FilterModel extends AbstractListModel {
private List items;
private List filteredItems;
public FilterModel() {
items = new ArrayList();
filteredItems = new ArrayList();
}
public void addElement(Object o) {//添加一个项到列表中
items.add(o);
refilter();//每添加一个项就更新filterItems
}
private void refilter() {
filteredItems.clear();
String item = getFilterField().getText();
for (int i = 0; i < items.size(); i++) {
if (items.get(i).toString().toUpperCase().indexOf(item, 0) != -1
|| items.get(i).toString().toLowerCase().indexOf(item,
0) != -1) {
filteredItems.add(items.get(i));
}
}
fireContentsChanged(this, 0, filteredItems.size());
}
@Override
public Object getElementAt(int index) {
if (index < filteredItems.size()) {
return filteredItems.get(index);
}
return null;
}
@Override
public int getSize() {
return filteredItems.size();
}
}
【FilterField】
private class FilterField extends JTextField implements DocumentListener {
public FilterField(int width) {
super(width);
getDocument().addDocumentListener(this);
}
@Override
public void changedUpdate(DocumentEvent e) {
model.refilter();//更新列表的显示数据,下同
}
@Override
public void insertUpdate(DocumentEvent e) {
model.refilter();
}
@Override
public void removeUpdate(DocumentEvent e) {
model.refilter();
}
}
【FilteredList】
public class FilteredList extends JList {
private FilterModel model;
private FilterField filterField;
public FilteredList() {
model = new FilterModel();
setModel(model);
filterField = new FilterField(20);
}
public void addItem(Object o) {
model.addElement(o);
}
public FilterField getFilterField() {
return filterField;
}
}
可见,FilteredList 实现起来非常的简单,只需定义前面已经创建出来的组件作为其属性。并更换Model。 使用自己实现的具有可过滤功能的Model。
下面是一段测试代码:
public static void main(String[] args) {
String[] listItems = { "Chris", "Joshua", "Daniel", "Michael", "Don",
"Kimi", "Kelly", "Keagan" };
JFrame frame = new JFrame("FilteredJList");
frame.getContentPane().setLayout(new BorderLayout());
// populate list
FilteredHistoryList list = new FilteredHistoryList();
for (int i = 0; i < listItems.length; i++)
list.addItem(listItems[i]);
// add to gui
JScrollPane pane = new JScrollPane(list,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
frame.getContentPane().add(pane, BorderLayout.CENTER);
frame.getContentPane().add(list.getFilterField(), BorderLayout.NORTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
【小结】
在这里实现的只是为一个JList附加了一层特定的功能,当然,我们不能停留在仅仅学会如何编写这功能的代码上,还要搞清楚内部如何实现,最终是为什么要 如此去做。
在这里,使用继承机制,接口实现等,都是利用类库成熟的组件类,如此就能复用很多特性。我们需要的是JList上加一层额外的功能,那么当然需要继承自 JList,使他俩具有血缘关系啦,方便管理吗!从这里也可以感受到Swing编码的一种感觉:数据与展示层划分清晰,展示与数据没有耦合在一块。当然, 可以说,在这个例子中没有做的很好,也没有作出具体的层次优化,读者可以自己试一试……
【参考资料】:《Swing Hacks》 By Chris Adamson , Joshua Marinacci
这篇关于具有可过滤功能的JList组件【Swing】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!