Componente per filtrare un elenco

Qual è il componente Java Swing adatto alla creazione di un elenco filtrabile come mostrato di seguito?

Questo tipo di filtraggio viene eseguito più facilmente utilizzando una singola colonna JTable . Una tabella ha funzionalità incorporate per aggiungere un RowSorter che:

.. fornisce le basi per l’ordinamento e il filtraggio.

Vedi anche Come usare le tabelle: ordinamento e filtraggio .

Ecco un esempio per filtrare i nomi delle famiglie di font:

inserisci la descrizione dell'immagine qui

A sinistra c’è un componente più ‘elenco in cerca’, mentre il lato destro mostra un componente che è chiaramente un tavolo.

Codice

 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); } } 

Se vuoi o devi usare solo componenti Swing standard, allora il metodo descritto da @AndrewThompson è la strada da percorrere.

Ma se sei in grado di utilizzare librerie di terze parti, una buona alternativa è il componente JXList incluso nel progetto SwingX . Questo componente è un’estensione JList e offre la possibilità di ordinare e filtrare il suo contenuto più altre interessanti funzionalità (controlla Demo SwingLabs ).

Il seguente frammento è la base per farlo funzionare:

 JXList list = new JXList(listModel); list.setAutoCreateRowSorter(true); 

Questo è sufficiente per creare e installare RowSorter come selezionatrice di riga dell’elenco che può essere recuperata chiamando il metodo getRowSorter() . L’object reale restituito da questo metodo è un ListSortController che eredita da DefaultRowSorter e implementa anche l’interfaccia SortController non standard.

È importante tenere a mente questa gerarchia di classi perché è ansible fornire un RowFilter in modi diversi. Tutte le seguenti alternative presuppongono che il sorter di riga sia stato creato automaticamente.

Nota: IMO il primo metodo è il preferito perché possiamo debind il lavoro sporco di down-casting del sorter di riga per fornire un filtro di riga al componente.

1. Imposta il filtro di riga direttamente nell’elenco

 list.setRowFilter(rowFilter); 

Questo è un metodo comodo per impostare il filtro di riga. Tuttavia, per contratto è richiesto che il selezionatore di righe dell’elenco reale sia SortController compatibile con SortController . In caso contrario, la setRowFilter(...) non ha alcun effetto.

2. SortController sorter di riga come SortController

 SortController sortController = (SortController)list.getRowSorter(); sortController.setRowFilter(rowFilter); 

L’interfaccia SortController fornisce un metodo per impostare il filtro di riga che è utilizzato per SortController il filtro di riga nel metodo # 1.

3. DefaultRowSorter sorter di riga come DefaultRowSorter

 DefaultRowSorter sorter = (DefaultRowSorter)list.getRowSorter(); sorter.setRowFilter(rowFilter); 

Questo metodo è lo stesso di quando lavoriamo con JTable .

Esempio

Ecco una semplice demo sul filtraggio con JXList . Ancora una volta, controlla le demo di SingLabs per ottenere esempi migliori.

 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() { @Override public boolean include(RowFilter.Entry 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(); } }); } }