I refactored the given code. It can recognize by the fragment. So "American English" and "English" are recognized when you put "English".
You could use the FilterComboBox class in your program.
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
/**
* A class for filtered combo box.
*/
public class FilterComboBox
extends JComboBox
{
/**
* Entries to the combobox list.
*/
private List<String> entries;
public List<String> getEntries()
{
return entries;
}
public FilterComboBox(List<String> entries)
{
super(entries.toArray());
this.entries = entries ;
this.setEditable(true);
final JTextField textfield =
(JTextField) this.getEditor().getEditorComponent();
/**
* Listen for key presses.
*/
textfield.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent ke)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
/**
* On key press filter the list.
* If there is "text" entered in text field of this combo use that "text" for filtering.
*/
comboFilter(textfield.getText());
}
});
}
});
}
/**
* Build a list of entries that match the given filter.
*/
public void comboFilter(String enteredText)
{
List<String> entriesFiltered = new ArrayList<String>();
for (String entry : getEntries())
{
if (entry.toLowerCase().contains(enteredText.toLowerCase()))
{
entriesFiltered.add(entry);
}
}
if (entriesFiltered.size() > 0)
{
this.setModel(
new DefaultComboBoxModel(
entriesFiltered.toArray()));
this.setSelectedItem(enteredText);
this.showPopup();
}
else
{
this.hidePopup();
}
}
}
See how FilterComboBox works in Demo program.
import javax.swing.JFrame;
import java.util.Arrays;
public class Demo
{
public static void makeUI()
{
JFrame frame = new JFrame("Your frame");
/**
* Put data to your filtered combobox.
*/
FilterComboBox fcb = new FilterComboBox(
Arrays.asList(
"",
"English",
"French",
"Spanish",
"Japanese",
"Chinese",
"American English",
"Canada French"
));
/**
* Set up the frame.
*/
frame.getContentPane().add(fcb);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) throws Exception
{
makeUI();
}
}
Another approach, where we make existing comboboxes to filtered comboboxes. It is somewhat "decoration".
"Decorator" class.
import java.util.List;
import java.util.ArrayList;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.DefaultComboBoxModel;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
/**
* Makes given combobox editable and filterable.
*/
public class JComboBoxDecorator
{
public static void decorate(final JComboBox jcb, boolean editable)
{
List<String> entries = new ArrayList<>();
for (int i = 0; i < jcb.getItemCount(); i++)
{
entries.add((String)jcb.getItemAt(i));
}
decorate(jcb, editable, entries);
}
public static void decorate(final JComboBox jcb, boolean editable, final List<String> entries)
{
jcb.setEditable(editable);
jcb.setModel(
new DefaultComboBoxModel(
entries.toArray()));
final JTextField textField = (JTextField) jcb.getEditor().getEditorComponent();
textField.addKeyListener(
new KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
comboFilter(textField.getText(), jcb, entries);
}
}
);
}
}
);
}
/**
* Build a list of entries that match the given filter.
*/
private static void comboFilter(String enteredText, JComboBox jcb, List<String> entries)
{
List<String> entriesFiltered = new ArrayList<String>();
for (String entry : entries)
{
if (entry.toLowerCase().contains(enteredText.toLowerCase()))
{
entriesFiltered.add(entry);
}
}
if (entriesFiltered.size() > 0)
{
jcb.setModel(
new DefaultComboBoxModel(
entriesFiltered.toArray()));
jcb.setSelectedItem(enteredText);
jcb.showPopup();
}
else
{
jcb.hidePopup();
}
}
}
Demonstration class.
import javax.swing.JFrame;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import javax.swing.JComboBox;
import javax.swing.JPanel;
public class Demo
{
public static void makeUI()
{
JFrame frame = new JFrame("Demonstration");
/**
* List of values for comboboxes.
*/
List<String> list = Arrays.asList(
"",
"English",
"French",
"Spanish",
"Japanese",
"Chinese",
"American English",
"Canada French"
);
List<String> list2 = Arrays.asList(
"",
"Anglais",
"Francais",
"Espagnol",
"Japonais",
"Chinois",
"Anglais americain",
"Canada francais"
);
/**
* Set up the frame.
*/
JPanel panel = new JPanel();
frame.add(panel);
/**
* Create ordinary comboboxes.
* These comboboxes represent premade combobox'es. Later in the run-time we make some of them filtered.
*/
JComboBox<String> jcb1 = new JComboBox<>(list.toArray(new String[0]));
panel.add(jcb1);
JComboBox<String> jcb2 = new JComboBox<>();
panel.add(jcb2);
JComboBox<String> jcb3 = new JComboBox<>(list2.toArray(new String[0]));
panel.add(jcb3);
/**
* On the run-time we convert second and third combobox'es to filtered combobox'es.
* The jcb1 combobox is left as it was.
* For the first decorated combobox supply our entries.
* For the other put entries from list2.
*/
JComboBoxDecorator.decorate(jcb2, true, list);
JComboBoxDecorator.decorate(jcb3, true);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) throws Exception
{
makeUI();
}
}