AutoComplete JComboBox
Posted by tech on
November 6, 2009
There are ready-made classes of JComboBox that implement an autocomplete feature and I chose to use Orbital Computer because of its ease of use and simplicity of the code. I added an extra feature in this JComboBox wherein if you press the ESC key, it will automatically select and show the first item in the ComboBoxModel.
To use this class, simply call it like this.
[... cb ...] new AutoCompleteJComboBoxer(cb);
That’s it! No need to actually create a variable for this class since you just pass the JComboBox object as the parameter and the class handles the rest adding the autocomplete feature. Pretty simple right? This is a handy class. Get the code below.
public class AutoCompleteJComboBoxer extends PlainDocument { private final JComboBox comboBox; private ComboBoxModel model; private JTextComponent editor; private boolean hidePopupOnFocusLoss; public AutoCompleteJComboBoxer(JComboBox comboBox) { this.comboBox = comboBox; comboBox.setEditable(true); model = comboBox.getModel(); editor = (JTextComponent) comboBox.getEditor().getEditorComponent(); editor.setDocument(this); // Bug 5100422 on Java 1.5: Editable JComboBox won't hide popup when tabbing out hidePopupOnFocusLoss = System.getProperty("java.version").startsWith("1.5"); // Highlight whole text when focus gets lost editor.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { highlightCompletedText(0); // Workaround for Bug 5100422 - Hide Popup on focus loss if (hidePopupOnFocusLoss) AutoCompleteJComboBoxer.this.comboBox.setPopupVisible(false); } }); // Highlight whole text when user hits enter editor.addKeyListener(new KeyAdapter() { @Override public void keyPressed(java.awt.event.KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { highlightCompletedText(0); } else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { AutoCompleteJComboBoxer.this.comboBox.setSelectedIndex(0); AutoCompleteJComboBoxer.this.editor.setText(AutoCompleteJComboBoxer.this.comboBox.getSelectedItem().toString()); highlightCompletedText(0); } } }); // Handle initially selected object Object selected = comboBox.getSelectedItem(); if (selected != null) editor.setText(selected.toString()); } @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { // construct the resulting string String currentText = getText(0, getLength()); String beforeOffset = currentText.substring(0, offs); String afterOffset = currentText.substring(offs, currentText.length()); String futureText = beforeOffset + str + afterOffset; // lookup and select a matching item Object item = lookupItem(futureText); if (item != null) { comboBox.setSelectedItem(item); } else { // keep old item selected if there is no match item = comboBox.getSelectedItem(); // imitate no insert (later on offs will be incremented by str.length(): selection won't move forward) offs = offs-str.length(); // provide feedback to the user that his input has been received but can not be accepted comboBox.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox); } // remove all text and insert the completed string super.remove(0, getLength()); super.insertString(0, item.toString(), a); // if the user selects an item via mouse the the whole string will be inserted. // highlight the entire text if this happens. if (item.toString().equals(str) && offs==0) { highlightCompletedText(0); } else { highlightCompletedText(offs+str.length()); // show popup when the user types comboBox.setPopupVisible(true); } } private void highlightCompletedText(int start) { editor.setCaretPosition(getLength()); editor.moveCaretPosition(start); } private Object lookupItem(String pattern) { Object selectedItem = model.getSelectedItem(); // only search for a different item if the currently selected does not match if (selectedItem != null && startsWithIgnoreCase(selectedItem.toString(), pattern)) { return selectedItem; } else { // iterate over all items for (int i=0, n=model.getSize(); i < n; i++) { Object currentItem = model.getElementAt(i); // current item starts with the pattern? if (startsWithIgnoreCase(currentItem.toString(), pattern)) { return currentItem; } } } // no item starts with the pattern => return null return null; } // checks if str1 starts with str2 - ignores case private boolean startsWithIgnoreCase(String str1, String str2) { return str1.toUpperCase().startsWith(str2.toUpperCase()); } }

/rating_on.png)
/rating_half.png)
(3 votes, average: 3.67 out of 5)






