Search code examples
javanetbeansjcombobox

editable JCombobox that filters the list and show only text that contains the text I wrote


I need to have an editable JCombobox that contains elements : example:

element 1
element 2
item one
item one two
element item

And when I write for example "one", It have to show me only

item one
item one two

All I found before are AutocompleteJCombobox which scrolls me to the items that starts with "one".

thank you in advance


Solution

  • Use e.g. algosome.com/articles/java-jcombobox-autocomplete.html replacing s.indexOf(value) == 0 with s.indexOf(value) >=0

    defining a searchable data structure:

    public interface Searchable<E, V>{
        public Collection<E> search(V value);
    }
    

    basic demonstration:

    public class StringSearchable implements Searchable<String,String>{
    
        private List<String> terms = new ArrayList<String>();
    
        public StringSearchable(List<String> terms){
            this.terms.addAll(terms);
        }
    
    
        @Override
        public Collection<String> search(String value) {
            List<String> founds = new ArrayList<String>();
    
            for ( String s : terms ){
                if ( s.indexOf(value) == 0 ){
                    founds.add(s);
                }
            }
            return founds;
        }
    }
    

    Now for the JComboBox auto-completion:

    public class AutocompleteJComboBox extends JComboBox{
        static final long serialVersionUID = 4321421L;
        private final Searchable<String,String> searchable;
    
        public AutocompleteJComboBox(Searchable<String,String> s){
            super();
            this.searchable = s;
            setEditable(true);
            Component c = getEditor().getEditorComponent();
    
            if ( c instanceof JTextComponent ){
                final JTextComponent tc = (JTextComponent)c;
                tc.getDocument().addDocumentListener(new DocumentListener(){
    
                    @Override
                    public void changedUpdate(DocumentEvent arg0) {}
    
                    @Override
                    public void insertUpdate(DocumentEvent arg0) {
                        update();
                    }
    
                    @Override
                    public void removeUpdate(DocumentEvent arg0) {
                        update();
                    }
    
                    public void update(){
                        SwingUtilities.invokeLater(new Runnable(){
    
                            @Override
                            public void run() {
                                List<String> founds = new ArrayList<String>(searchable.search(tc.getText()));
                                Set<String> foundSet = new HashSet<String>();
                                for ( String s : founds ){
                                    foundSet.add(s.toLowerCase());
                                }
                                Collections.sort(founds);//sort alphabetically
                                setEditable(false);
                                removeAllItems();
                                //if founds contains the search text, then only add once.
    
                                if ( !foundSet.contains( tc.getText().toLowerCase()) ){
                                    addItem( tc.getText() );
                                }                           
    
                                for (String s : founds) {
                                    addItem(s);
                                }
                                setEditable(true);
                                setPopupVisible(true);
                            }
                        });
                    }
                });
    
                tc.addFocusListener(new FocusListener(){
    
                    @Override
                    public void focusGained(FocusEvent arg0) {
                        if ( tc.getText().length() > 0 ){
                            setPopupVisible(true);
                        }
                    }
    
                    @Override
                    public void focusLost(FocusEvent arg0) {                        
                    }
                });
            }else{
                throw new IllegalStateException("Editing component is not a JTextComponent!");
            }
        }
    }