用于过滤列表的组件
什么是适合创build一个可过滤的列表,如下所示的Java Swing组件?
这种types的过滤最容易使用单个列JTable
。 一个表具有内置function来添加RowSorter
,其中:
为sorting和过滤提供了依据。
另请参见如何使用表:sorting和筛选 。
以下是过滤字体名称的示例:
左边是更多的“清单查看”组件,右边则显示了一个清晰可见的组件。
码
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
组件就是一个很好的select。 这个组件是一个JList
扩展,并提供sorting和过滤其内容以及其他有趣function(检查SwingLabs演示 )的function。
以下片段是使其工作的基础:
JXList list = new JXList(listModel); list.setAutoCreateRowSorter(true);
这足以创build和安装RowSorter<ListModel, Integer>
实例作为列表的行分类器,可以通过调用getRowSorter()
方法来检索它。 这个方法返回的实际对象是一个ListSortController
,它inheritance自DefaultRowSorter
,同时也实现了非标准的SortController
接口。
记住这个类层次是很重要的,因为可以用不同的方式提供一个RowFilter
。 以下所有替代方法假定行分拣机是自动创build的。
注意: IMO第一种方法是首选方法,因为我们可以委托向下排放行分拣机的脏工作来为组件提供行filter。
1.直接在列表中设置行筛选器
list.setRowFilter(rowFilter);
这是设置行filter的一种方便方法。 但是合同要求实际列表的行分类器是一个SortController
兼容的实例。 否则, setRowFilter(...)
调用不起作用。
2.将行分拣机转换为SortController
SortController<ListModel> sortController = (SortController<ListModel>)list.getRowSorter(); sortController.setRowFilter(rowFilter);
SortController
接口提供了一种方法来设置用于旁路方法#1中的行filter的行filter。
3.将行分拣机转换为DefaultRowSorter
DefaultRowSorter<ListModel, Integer> sorter = (DefaultRowSorter<ListModel, Integer>)list.getRowSorter(); sorter.setRowFilter(rowFilter);
这个方法与我们使用JTable
方法相同。
例
这里是一个关于使用JXList
过滤的简单演示。 请再次检查SingLabs演示以获取更好的示例。
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(); } }); } }