JComboBox 搜索列表

JComboBox search list

我想要 JComboBox 可以搜索内容。 我试过AutoCompleteDecorator, GlazedLists, SwingLabs, JIDE, Laf-Widget,但都无法通过第二个关键字搜索。 例如,在此代码中可以按第一个字母搜索,并且此内容仅包含一个词。

this.comboBox = new JComboBox(new Object[] { "Ester", "Jordi", "Jordina", "Jorge", "Sergi" });
AutoCompleteDecorator.decorate(this.comboBox);

如果JComboBox内容由2或3个词组成,例如:"Ester Jordi"或"Jorge Sergi",在这种情况下如果我输入"Sergi",JComboBox不要什么都不显示,因为它可以通过第一个词识别。 请问有什么办法可以解决这个问题吗?

我重构了给定的代码。它可以通过片段识别。所以当你输入 "English".

时,"American English" 和 "English" 会被识别

您可以在您的程序中使用 FilterComboBox class。

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

/**
 * A class for filtered combo box.
 */
public class FilterComboBox
    extends JComboBox
{
    /**
     * Entries to the combobox list.
     */
    private List<String> entries;

    public List<String> getEntries()
    {
        return entries;
    }

    public FilterComboBox(List<String> entries)
    {
        super(entries.toArray());
        this.entries = entries  ;
        this.setEditable(true);

        final JTextField textfield =
            (JTextField) this.getEditor().getEditorComponent();

        /**
         * Listen for key presses.
         */
        textfield.addKeyListener(new KeyAdapter()
        {
            public void keyReleased(KeyEvent ke)
            {
                SwingUtilities.invokeLater(new Runnable()
                {
                    public void run()
                    {
                        /**
                         * On key press filter the list.
                         * If there is "text" entered in text field of this combo use that "text" for filtering.
                         */
                        comboFilter(textfield.getText());
                    }
                });
            }
        });

    }

    /**
     * Build a list of entries that match the given filter.
     */
    public void comboFilter(String enteredText)
    {
        List<String> entriesFiltered = new ArrayList<String>();

        for (String entry : getEntries())
        {
            if (entry.toLowerCase().contains(enteredText.toLowerCase()))
            {
                entriesFiltered.add(entry);
            }
        }

        if (entriesFiltered.size() > 0)
        {
            this.setModel(
                    new DefaultComboBoxModel(
                        entriesFiltered.toArray()));
            this.setSelectedItem(enteredText);
            this.showPopup();
        }
        else
        {
            this.hidePopup();
        }
    }
}

在 Demo 程序中查看 FilterComboBox 的工作原理。

import javax.swing.JFrame;
import java.util.Arrays;

public class Demo
{
    public static void makeUI()
    {
        JFrame frame = new JFrame("Your frame");
        /**
         * Put data to your filtered combobox.
         */
        FilterComboBox fcb = new FilterComboBox(
                Arrays.asList(
                    "",
                    "English", 
                    "French", 
                    "Spanish", 
                    "Japanese",
                    "Chinese",
                    "American English",
                    "Canada French"
                    ));
        /**
         * Set up the frame.
         */
        frame.getContentPane().add(fcb);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static void main(String[] args) throws Exception
    {
        makeUI();
    }
}

另一种方法,我们将现有的组合框变成过滤后的组合框。有点"decoration".

"Decorator" class.

import java.util.List;
import java.util.ArrayList;

import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.DefaultComboBoxModel;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

/**
 * Makes given combobox editable and filterable.
 */ 
public class JComboBoxDecorator
{
    public static void decorate(final JComboBox jcb, boolean editable)
    {
        List<String> entries = new ArrayList<>();
        for (int i = 0; i < jcb.getItemCount(); i++)
        {
            entries.add((String)jcb.getItemAt(i));
        }

        decorate(jcb, editable, entries);
    }

    public static void decorate(final JComboBox jcb, boolean editable, final List<String> entries)
    {
        jcb.setEditable(editable);
        jcb.setModel(
                    new DefaultComboBoxModel(
                        entries.toArray()));

        final JTextField textField = (JTextField) jcb.getEditor().getEditorComponent();

        textField.addKeyListener(
            new KeyAdapter()
            {
                public void keyReleased(KeyEvent e)
                {
                    SwingUtilities.invokeLater(
                        new Runnable()
                        {
                            public void run()
                            { 
                                comboFilter(textField.getText(), jcb, entries);
                            }
                        }
                    );
                } 
            }
        );
    }

    /**
     * Build a list of entries that match the given filter.
     */
    private static void comboFilter(String enteredText, JComboBox jcb, List<String> entries)
    {
        List<String> entriesFiltered = new ArrayList<String>();

        for (String entry : entries)
        {
            if (entry.toLowerCase().contains(enteredText.toLowerCase()))
            {
                entriesFiltered.add(entry);
            }
        }

        if (entriesFiltered.size() > 0)
        {
            jcb.setModel(
                    new DefaultComboBoxModel(
                        entriesFiltered.toArray()));
            jcb.setSelectedItem(enteredText);
            jcb.showPopup();
        }
        else
        {
            jcb.hidePopup();
        }
    }

}

示范[​​=31=].

import javax.swing.JFrame;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;

import javax.swing.JComboBox;
import javax.swing.JPanel;

public class Demo
{
    public static void makeUI()
    {
        JFrame frame = new JFrame("Demonstration");

        /**
         * List of values for comboboxes.
         */
        List<String> list = Arrays.asList( 
            "",
            "English", 
            "French", 
            "Spanish", 
            "Japanese",
            "Chinese",
            "American English",
            "Canada French"
        );

        List<String> list2 = Arrays.asList( 
            "",
            "Anglais", 
            "Francais", 
            "Espagnol", 
            "Japonais",
            "Chinois",
            "Anglais americain",
            "Canada francais"
        );

        /**
         * Set up the frame.
         */
        JPanel panel = new JPanel();
        frame.add(panel);

        /**
         * Create ordinary comboboxes.
         * These comboboxes represent premade combobox'es. Later in the run-time we make some of them filtered.
         */
        JComboBox<String> jcb1 = new JComboBox<>(list.toArray(new String[0]));
        panel.add(jcb1);

        JComboBox<String> jcb2 = new JComboBox<>();
        panel.add(jcb2);

        JComboBox<String> jcb3 = new JComboBox<>(list2.toArray(new String[0]));
        panel.add(jcb3);

        /**
         * On the run-time we convert second and third combobox'es to filtered combobox'es.
         * The jcb1 combobox is left as it was.
         * For the first decorated combobox supply our entries.
         * For the other put entries from list2.
         */
        JComboBoxDecorator.decorate(jcb2, true, list); 
        JComboBoxDecorator.decorate(jcb3, true); 

        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static void main(String[] args) throws Exception
    {
        makeUI();
    }
}

在尝试执行的时候遇到了两个问题:

  • 当按下键盘上的(向上、向下、输入)按钮时。我通过阻止他们使用 return 语句来解决它。

  • 每次在文本字段中写入时都会触发 popupMenuWillBecomeInvisble()。 我通过在 popupMenuWillBecomeInvisible

    内的主框架中添加 getKeyStat() 解决了这个问题

希望对您有所帮助!

   private voidjCombobox1popupMenuWillBecomeInvisble(javax.swing.event.PopupMenuEvent evt){
         if(JComboBoxDecorator.getKeyStat().equals("enter")){
           //write yor code here
        }
        }

import java.util.List;
import java.util.ArrayList;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.DefaultComboBoxModel;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.SwingUtilities;

/**
 * Makes given combo box editable and filterable.
 */
public class JComboBoxDecorator {
    static String checkenter="";
    
    public static String getKeyStat(){
       return checkenter;
    }
    
    public static void decorate(final JComboBox jcb, boolean editable) {
        List<String> entries = new ArrayList<>();
        for (int i = 0; i < jcb.getItemCount(); i++) {
            entries.add((String) jcb.getItemAt(i));
        }

        decorate(jcb, editable, entries);
    }
    
    public static void decorate(final JComboBox jcb, boolean editable, final List<String> entries) {
        jcb.setEditable(editable);
        jcb.setModel(new DefaultComboBoxModel(entries.toArray()));

        final JTextField textField = (JTextField) jcb.getEditor().getEditorComponent();

        textField.addKeyListener(
                new KeyAdapter() {
                    @Override
                    public void keyPressed(KeyEvent e) {
                     if(e.getKeyCode() == KeyEvent.VK_ENTER){
                         checkenter = "enter";
                     }
                    }
            @Override
            public void keyReleased(KeyEvent e) {
                SwingUtilities.invokeLater(() -> {
                   if(e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode()==KeyEvent.VK_ENTER){
                      // e.consume();
                       return ;                       
                   }  
                   else{ 
                       comboFilter(textField.getText(), jcb, entries);
                   }
                    
                });
                checkenter = "type";
            }
        }
        );
    }

    /**
     * Build a list of entries that match the given filter.
     */
    private static void comboFilter(String enteredText, JComboBox jcb, List<String> entries) {
        List<String> entriesFiltered = new ArrayList<>();

        for (String entry : entries) {
            if (entry.toLowerCase().contains(enteredText.toLowerCase())) {
                entriesFiltered.add(entry);
            }
        }

        if (entriesFiltered.size() > 0) {
            jcb.setModel(
                    new DefaultComboBoxModel(
                            entriesFiltered.toArray()));
            jcb.setSelectedItem(enteredText);
            jcb.showPopup();
            
        } else {
            jcb.hidePopup();
        }
    }

}