Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Autocomplete Combobox In Java With Filtering And Inserting New Text

DZone's Guide to

Autocomplete Combobox In Java With Filtering And Inserting New Text

· Java Zone
Free Resource

Bitbucket is for the code that takes us to Mars, decodes the human genome, or drives your next car. What will your code do? Get started with Bitbucket today, it's free.



import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.PlainDocument;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

/**
 * Autocomplete combobox with filtering and
 * text inserting of new text
 * @author Exterminator13
 */
public class AutoCompleteCombo extends JComboBox{

    private static final Logger logger = Logger.getLogger(AutoCompleteCombo.class);
    private Model model = new Model();
    private final JTextComponent textComponent = (JTextComponent) getEditor().getEditorComponent();
    private boolean modelFilling = false;

    private boolean updatePopup;

    public AutoCompleteCombo() {

        setEditable(true);

        logger.debug("setPattern() called from constructor");
        setPattern(null);
        updatePopup = false;

        textComponent.setDocument(new AutoCompleteDocument());
        setModel(model);
        setSelectedItem(null);

        new Timer(20, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (updatePopup && isDisplayable()) {
                    setPopupVisible(false);
                    if (model.getSize() > 0) {
                        setPopupVisible(true);
                    }
                    updatePopup = false;
                }
            }
        }).start();
    }

      private class AutoCompleteDocument extends PlainDocument {

        boolean arrowKeyPressed = false;

        public AutoCompleteDocument() {
            textComponent.addKeyListener(new KeyAdapter() {

                @Override
                public void keyPressed(KeyEvent e) {
                    int key = e.getKeyCode();
                    if (key == KeyEvent.VK_ENTER) {
                        logger.debug("[key listener] enter key pressed");
                        //there is no such element in the model for now
                        String text = textComponent.getText();
                        if (!model.data.contains(text)) {
                            logger.debug("addToTop() called from keyPressed()");
                            addToTop(text);
                        }
                    } else if (key == KeyEvent.VK_UP ||
                               key == KeyEvent.VK_DOWN) {
                        arrowKeyPressed = true;
                        logger.debug("arrow key pressed");
                    }
                }
            });
        }

        void updateModel() throws BadLocationException {
            String textToMatch = getText(0, getLength());
            logger.debug("setPattern() called from updateModel()");
            setPattern(textToMatch);
        }

        @Override
        public void remove(int offs, int len) throws BadLocationException {

            if (modelFilling) {
                logger.debug("[remove] model is being filled now");
                return;
            }

            super.remove(offs, len);
            if (arrowKeyPressed) {
                arrowKeyPressed = false;
                logger.debug("[remove] arrow key was pressed, updateModel() was NOT called");
            } else {
                logger.debug("[remove] calling updateModel()");
                updateModel();
            }
            clearSelection();
        }

        @Override
        public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {

            if (modelFilling) {
                logger.debug("[insert] model is being filled now");
                return;
            }

            // insert the string into the document
            super.insertString(offs, str, a);

//            if (enterKeyPressed) {
//                logger.debug("[insertString] enter key was pressed");
//                enterKeyPressed = false;
//                return;
//            }

            String text = getText(0, getLength());
            if (arrowKeyPressed) {
                logger.debug("[insert] arrow key was pressed, updateModel() was NOT called");
                model.setSelectedItem(text);
                logger.debug( String.format("[insert] model.setSelectedItem(%s)", text) );
                arrowKeyPressed = false;
            } else if(!text.equals(getSelectedItem())){
                logger.debug("[insert] calling updateModel()");
                updateModel();
            }

            clearSelection();
        }

    }


    public void setText(String text) {
        if (model.data.contains(text)) {
            setSelectedItem(text);
        } else {
            addToTop(text);
            setSelectedIndex(0);
        }
    }

    public String getText() {
        return getEditor().getItem().toString();
    }

    private String previousPattern = null;

    private void setPattern(String pattern) {

        if(pattern!=null && pattern.trim().isEmpty())
            pattern = null;

        if(previousPattern==null && pattern ==null ||
           pattern!=null && pattern.equals(previousPattern)) {
            logger.debug("[setPatter] pattern is the same as previous: "+previousPattern);
            return;
        }

        previousPattern = pattern;

        modelFilling = true;
//        logger.debug("setPattern(): start");

        model.setPattern(pattern);

        if(logger.isDebugEnabled()) {
            StringBuilder b = new StringBuilder(100);
            b.append("pattern filter '").append(pattern==null ? "null" : pattern).append("' set:\n");
            for(int i=0; i list = new ArrayList(limit);
            private List lowercase = new ArrayList(limit);
            private List filtered;

            void add(String s) {
                list.add(s);
                lowercase.add(s.toLowerCase());
            }

            void addToTop(String s) {
                list.add(0, s);
                lowercase.add(0, s.toLowerCase());
            }

            void remove(int index) {
                list.remove(index);
                lowercase.remove(index);
            }

            List getList() {
                return list;
            }

            List getFiltered() {
                if(filtered==null)
                    filtered = list;
                return filtered;
            }

            int size() {
                return list.size();
            }

            void setPattern(String pattern) {
                if (pattern == null || pattern.isEmpty()) {
                    filtered = list;
                    AutoCompleteCombo.this.setSelectedItem(model.getElementAt(0));
                    logger.debug( String.format("[setPattern] combo.setSelectedItem(null)") );
                } else {
                    filtered = new ArrayList(limit);
                    pattern = pattern.toLowerCase();
                    for(int i=0; isize2) {
                fireIntervalRemoved(this, size2, size1-1);
                fireContentsChanged(this, 0, size2-1);
            }
        }

        public void addToTop(String aString) {
            if(aString==null || data.contains(aString))
                return;
            if(data.size()==0)
                data.add(aString);
            else
                data.addToTop(aString);

            while(data.size()>limit) {
                int index = data.size()-1;
                data.remove(index);
            }

            setPattern(null);
            model.setSelectedItem(aString);
            logger.debug( String.format("[addToTop] model.setSelectedItem(%s)", aString) );

            //saving into options
            if (data.size() > 0) {
                writeData();
            }
        }

        @Override
        public Object getSelectedItem() {
            return selected;
        }

          @Override
          public void setSelectedItem(Object anObject) {
              if ((selected != null && !selected.equals(anObject)) ||
                      selected == null && anObject != null) {
                  selected = (String) anObject;
                  fireContentsChanged(this, -1, -1);
              }
          }

        @Override
        public int getSize() {
            return data.getFiltered().size();
        }

        @Override
        public Object getElementAt(int index) {
            return data.getFiltered().get(index);
        }

    }



    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {

//                Logger root = Logger.getRootLogger();
//                root.addAppender(new ConsoleAppender(new PatternLayout("%d{ISO8601} [%5p] %m at %l%n")));
                Logger root = Logger.getRootLogger();
                root.addAppender(new ConsoleAppender(new PatternLayout("%d{ISO8601} %m at %L%n")));

//                BasicConfigurator.configure();

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridLayout(3, 1));
                final JLabel label = new JLabel("label ");
                frame.add(label);
                final AutoCompleteCombo combo = new AutoCompleteCombo();
//                combo.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
//
//                    @Override
//                    public void keyReleased(KeyEvent e) {
//                        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
//                            String text = combo.getEditor().getItem().toString();
//                            if(text.isEmpty())
//                                return;
//                            combo.addToTop(text);
//                        }
//                    }
//                });
                frame.add(combo);
                JComboBox combo2 = new JComboBox(new String[] {"Item 1", "Item 2", "Item 3", "Item 4"});
                combo2.setEditable(true);
                frame.add(combo2);
                frame.pack();
                frame.setSize( 500, frame.getHeight() );
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}



Are you using Bitbucket to accomplish your company's mission? Share your company’s mission with #Forthecode for a chance to be featured on our homepage, our social media channels, or win a free t-shirt!

Topics:
java

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}