【发布时间】:2015-02-20 04:27:12
【问题描述】:
适合创建如下所示可过滤列表的 Java Swing 组件是什么?
【问题讨论】:
适合创建如下所示可过滤列表的 Java Swing 组件是什么?
【问题讨论】:
这种类型的过滤使用单个列JTable 最容易完成。表格具有添加 RowSorter 的内置功能:
..提供排序和过滤的基础。
另见How to Use Tables: Sorting and Filtering。
以下是过滤字体系列名称的示例:
左侧是一个更像“列表”的组件,而右侧显示的组件显然是一个表格。
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.*;
import javax.swing.text.Document;
import javax.swing.table.TableRowSorter;
public class FontFilter {
private JComponent ui = null;
JTextField filterText;
TableRowSorter sorter;
FontFilter(boolean listLike) {
initUI(listLike);
}
public void initUI(boolean listLike) {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
GraphicsEnvironment ge
= GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fonts = ge.getAvailableFontFamilyNames();
String[][] tableData = new String[fonts.length][1];
for (int i = 0; i < fonts.length; i++) {
tableData[i][0] = fonts[i];
}
String[] header = {"Fonts"};
JTable table = new JTable(tableData, header);
if (listLike) {
Dimension d = table.getPreferredScrollableViewportSize();
table.setPreferredScrollableViewportSize(new Dimension(d.width/2,d.height));
table.setShowGrid(false);
table.setTableHeader(null);
table.setFillsViewportHeight(true);
}
ui.add(new JScrollPane(table));
sorter = new TableRowSorter(table.getModel());
table.setRowSorter(sorter);
filterText = new JTextField(10);
ui.add(filterText, BorderLayout.PAGE_START);
Document doc = filterText.getDocument();
DocumentListener listener = new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
newFilter();
}
@Override
public void removeUpdate(DocumentEvent e) {
newFilter();
}
@Override
public void changedUpdate(DocumentEvent e) {
newFilter();
}
};
doc.addDocumentListener(listener);
}
private void newFilter() {
RowFilter rf = null;
//If current expression doesn't parse, don't update.
try {
rf = RowFilter.regexFilter(filterText.getText(), 0);
} catch (java.util.regex.PatternSyntaxException e) {
return;
}
sorter.setRowFilter(rf);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
FontFilter o1 = new FontFilter(true);
FontFilter o2 = new FontFilter(false);
JFrame f = new JFrame("Font Filter");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.add(o1.getUI(), BorderLayout.LINE_START);
f.add(o2.getUI(), BorderLayout.CENTER);
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
【讨论】:
如果您想或必须只使用标准 Swing 组件,那么@AndrewThompson 描述的方法是可行的方法。
但是如果您能够使用第三方库,那么一个不错的选择是包含在SwingX 项目中的JXList 组件。该组件是JList 扩展,提供对其内容进行排序和过滤的能力以及其他有趣的功能(请查看SwingLabs Demos)。
下面的sn-p是让它工作的基础:
JXList list = new JXList(listModel);
list.setAutoCreateRowSorter(true);
这足以创建和安装一个RowSorter<ListModel, Integer> 实例作为列表的行排序器,可以通过调用getRowSorter() 方法来检索它。该方法返回的实际对象是一个ListSortController,它继承自DefaultRowSorter,并且还实现了非标准的SortController接口。
记住这个类层次结构很重要,因为可以以不同的方式提供RowFilter。以下所有备选方案都假定行排序器是自动创建的。
注意: IMO 第一种方法是首选方法,因为我们可以委派向下转换行排序器以向组件提供行过滤器的繁琐工作。
list.setRowFilter(rowFilter);
这是一种设置行过滤器的便捷方法。但是,合同要求实际列表的行排序器是符合SortController 的实例。否则setRowFilter(...) 调用无效。
SortController
SortController<ListModel> sortController
= (SortController<ListModel>)list.getRowSorter();
sortController.setRowFilter(rowFilter);
SortController接口提供了一种设置行过滤器的方法,用于绕过方法#1中的行过滤器。
DefaultRowSorter
DefaultRowSorter<ListModel, Integer> sorter
= (DefaultRowSorter<ListModel, Integer>)list.getRowSorter();
sorter.setRowFilter(rowFilter);
此方法与我们使用 JTable 时的方法相同。
这是一个关于使用JXList 进行过滤的简单演示。请再次查看SingLabs Demos 以获得更好的示例。
import java.awt.BorderLayout;
import java.awt.GraphicsEnvironment;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.jdesktop.swingx.JXList;
public class FilterListDemo {
private JXList list;
private void createAndShowGui() {
final JTextField filterText = new JTextField(30);
filterText.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
FilterListDemo.this.createFilter(filterText.getText(), false);
}
@Override
public void removeUpdate(DocumentEvent e) {
FilterListDemo.this.createFilter(filterText.getText(), false);
}
@Override
public void changedUpdate(DocumentEvent e) {
FilterListDemo.this.createFilter(filterText.getText(), false);
}
});
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fonts = ge.getAvailableFontFamilyNames();
list = new JXList(fonts);
list.setAutoCreateRowSorter(true);
JPanel content = new JPanel(new BorderLayout(8,8));
content.add(filterText, BorderLayout.PAGE_START);
content.add(new JScrollPane(list), BorderLayout.CENTER);
content.setBorder(BorderFactory.createEmptyBorder(8,8,8,8));
JFrame frame = new JFrame("Filter List Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(content);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void createFilter(String text, final boolean caseSensitive) {
final String filterText = caseSensitive ? text : text.toUpperCase();
list.setRowFilter(new RowFilter<ListModel, Integer>() {
@Override
public boolean include(RowFilter.Entry<? extends ListModel
, ? extends Integer> entry) {
String entryValue = caseSensitive
? entry.getStringValue(0)
: entry.getStringValue(0).toUpperCase();
return filterText == null
|| filterText.trim().isEmpty()
|| entryValue.contains(filterText.trim());
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new FilterListDemo().createAndShowGui();
}
});
}
}
【讨论】: