可编辑的 JCombobox,用于过滤列表并仅显示包含我编写的文本的文本

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

我需要一个包含元素的可编辑 JCombobox:示例:

element 1
element 2
item one
item one two
element item

当我写例如 "one" 时,它必须只显示给我

item one
item one two

我之前找到的所有内容都是 AutocompleteJCombobox,它将我滚动到以 "one".

开头的项目

提前致谢

使用例如algosome.com/articles/java-jcombobox-autocomplete.html 将 s.indexOf(value) == 0 替换为 s.indexOf(value) >=0

定义可搜索的数据结构:

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

基本演示:

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;
    }
}

现在 JComboBox 自动完成:

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!");
        }
    }
}

StanislavL 的 AutocompleteJComboBox 在与同一 Window 中的其他组件一起使用时在键入时失去焦点(至少在我的情况下)。
不过有一个简单的解决方法——添加一个 requestFocus();在 运行 函数的末尾。

添加的代码:

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);
                        requestFocus();
                    }
                });
            }
        });

        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!");
    }
}
}