Java Swing Dynamic Combo Box (suggestion box)

I think we can all agree that it’s a great user experience to have dynamically updated and populated dropdowns for user input. Especially if the user has a large choice of selections, or there are many similar ones. Or even if the user is unsure of what to type. It is especially usefull for search suggestions. you can apply any logic to the dynamic display, not necessarily based on alphabetical or matching searches (although I don’t know how useful this would be…)

So here’s some code for creating a dynamically populated JComboBox (a la google search hints). It uses a fixed array of items for demo purposes, but you can simply replace the code in the updateModel(String in) method (of the combobox model) with your own database query or whatever you need to do to grab your data.


The basics are : 1 create a JComboBox like usual. Set the combobox model to be an instance of the SearchBoxModel. Finally add an Item listener (the same instance of SearchBoxModel) to the combobox.

Some workarounds in this are : the popup is hidden and then displayed whenever the list data changes to get around redraw problems when the popup list items expand or reduce when the popup is visible. It is not noticeable in this demo, but perhaps if your item list is extensive it may pose an issue. If you do have a problem, I’d like to hear from you :)

To do this, wherever you create your combo box, set it up as follows :

//create the combobox
JComboBox searchbox = new JCombobox();
//we need it to be editable!!
searchbox.setEditable(true);
//create the model
SearchBoxModel sbm = new SearchBoxModel(searchbox);
//set the model on the combobox
searchbox.setModel(sbm);
//set the model as the item listener also
searchbox.addItemListener(sbm)

Below is the source code for the combo box model.




import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxEditor;
import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;


public class SearchBoxModel extends AbstractListModel 
                implements ComboBoxModel, KeyListener, ItemListener
{
    ArrayList<String> db = new ArrayList<String>();
    ArrayList<String> data = new ArrayList<String>();
    String selection;
    JComboBox cb;
    ComboBoxEditor cbe;
    int currPos = 0;


    public SearchBoxModel(JComboBox jcb)
    {
        
        cb = jcb;
        cbe = jcb.getEditor();
//here we add the key listener to the text field that the combobox is wrapped around
        cbe.getEditorComponent().addKeyListener(this);

//set up our "database" of items - in practice you will usuallu have a proper db.
        db.add("aluminium");
        db.add("iron");
        db.add("iron oxide (2+)");
        db.add("iron oxide (3+)");
        db.add("sodium");
        db.add("sodium chloride");
        db.add("titanium");
        db.add("selenium");
        db.add("potassium");
        db.add("polonium");
        db.add("aluminium chloride");
    }

    public void updateModel(String in)
    {
        data.clear();
//lets find any items which start with the string the user typed, and add it to the popup list
//here you would usually get your items from a database, or some other storage...
        for(String s:db)
            if(s.startsWith(in))
                data.add(s);

        super.fireContentsChanged(this, 0, data.size());

//this is a hack to get around redraw problems when changing the list length of the displayed popups
        cb.hidePopup();
        cb.showPopup();
        if(data.size() != 0)
            cb.setSelectedIndex(0);
    }

    public int getSize(){return data.size();}
    public Object getElementAt(int index){return data.get(index);}
    public void setSelectedItem(Object anItem)
                                 {selection = (String) anItem;}
    public Object getSelectedItem(){return selection;}
    public void keyTyped(KeyEvent e){}
    public void keyPressed(KeyEvent e){}

    public void keyReleased(KeyEvent e)
    {
        String str = cbe.getItem().toString();
        JTextField jtf = (JTextField)cbe.getEditorComponent();
        currPos = jtf.getCaretPosition();

        if(e.getKeyChar() == KeyEvent.CHAR_UNDEFINED)
        {
            if(e.getKeyCode() != KeyEvent.VK_ENTER )
            {
                cbe.setItem(str);
                jtf.setCaretPosition(currPos);
            }
        }
        else if(e.getKeyCode() == KeyEvent.VK_ENTER)
            cb.setSelectedIndex(cb.getSelectedIndex());
        else
        {
            updateModel(cb.getEditor().getItem().toString());
            cbe.setItem(str);
            jtf.setCaretPosition(currPos);
        }
    }

    public void itemStateChanged(ItemEvent e)
    {
        cbe.setItem(e.getItem().toString());
        cb.setSelectedItem(e.getItem());
    }

}