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:
A sinistra c’è un componente più ‘elenco in cerca’, mentre il lato destro mostra un componente che è chiaramente un tavolo.
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.
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.
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.
DefaultRowSorter
sorter di riga come DefaultRowSorter
DefaultRowSorter sorter = (DefaultRowSorter)list.getRowSorter(); sorter.setRowFilter(rowFilter);
Questo metodo è lo stesso di quando lavoriamo con JTable
.
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 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(); } }); } }