Buggy JCombobox-KeyPressed

时间:2018-08-22 19:31:59

标签: java jcombobox keypress

对于包含一些以重复字母开头的元素的JComboBox,键入两次字符将返回键入的字符,然后是其类型的第一个字符。例如,在包含ba,bb和bc的列表中键入“ bb”将返回ba。但是,如果此列表还包含bbd,则继续按“ d”将返回bbd选项。这与数字相同:键入“ 33”将返回30,而键入“ 334”将返回334。

是否可以解决此问题,以便double keyPress真正返回键入的内容?

快速示例程序:

String[] range = new String[401];
for (int i = 0; i <= 400; i++) {
        range[i] = "" + i;
}

private javax.swing.JComboBox<String> jComboBox1;
jComboBox1 = new javax.swing.JComboBox<>();
getContentPane().setLayout(new java.awt.GridLayout());

jComboBox1.setModel(new javax.swing.DefaultComboBoxModel<>(range));
getContentPane().add(jComboBox1);

pack();

1 个答案:

答案 0 :(得分:3)

通过键盘选择项目由JComboBox.KeySelectionManager控制,令人惊讶的是,您实际上可以实现和更改

默认实现的一件事是,它将尝试根据项的第一个字符(通过String转换为toString)找到与按键匹配的项。与此相关的“整洁”事情是,它将从当前选定的项目(如果不是null)中进行搜索,如果找不到其他匹配的项目,它将从模型的开头开始。

这意味着,如果您反复键入3,它将逐步遍历以3开头的所有项目。 ({303132 ... 39300 ...)

Buuuut,这显然不是您想要的,因此,您将不得不提供自己的算法。

一个非常重要的考虑因素是,当用户停止键入时会发生什么?如果用户键入了33,然后停止,然后再次键入3,应该怎么办?应该选择3还是333

以下是一个非常基本的示例,基于默认情况下DefaultKeySelectionManager使用的JComoBox。它使用StringBuilder来跟踪击键,并使用Swing Timer提供250毫秒的超时,它将在StringBuilder毫秒后清除250不活动状态(您可以将此值传递给构造函数以定义自己的值)

JComboBox调用时,它将简单地在模型中线性搜索其toString结果以键入的内容开头的项目。

此示例不区分大小写,但您可以对其进行修改以满足您的特定需求

public class MyKeySelectionManager implements KeySelectionManager {

    private Timer timeout;
    private StringBuilder pattern = new StringBuilder(32);

    public MyKeySelectionManager() {
        timeout = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                pattern.delete(0, pattern.length());
            }
        });
        timeout.setRepeats(false);
    }

    @Override
    public int selectionForKey(char aKey, ComboBoxModel<?> model) {
        timeout.stop();
        pattern.append(Character.toLowerCase(aKey));
        String match = pattern.toString();
        for (int index = 0; index < model.getSize(); index++) {
            String text = model.getElementAt(index).toString().toLowerCase();
            if (text.startsWith(match)) {
                timeout.start();
                return index;
            }
        }

        timeout.start();
        return -1;
    }

}

可运行的示例

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JComboBox.KeySelectionManager;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
                for (int index = 0; index < 50; index++) {
                    model.addElement(Integer.toString(index));
                }

                JComboBox cb = new JComboBox(model);
                cb.setKeySelectionManager(new MyKeySelectionManager());
                JFrame frame = new JFrame();
                JPanel content = new JPanel(new GridBagLayout());
                content.setBorder(new EmptyBorder(32, 32, 32, 32));
                content.add(cb);
                frame.setContentPane(content);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MyKeySelectionManager implements KeySelectionManager {

        private Timer timeout;
        private StringBuilder pattern = new StringBuilder(32);

        public MyKeySelectionManager() {
            timeout = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    pattern.delete(0, pattern.length());
                }
            });
            timeout.setRepeats(false);
        }

        protected int indexOf(Object item, ComboBoxModel<?> model) {
            for (int index = 0; index < model.getSize(); index++) {
                if (model.getElementAt(index) == item) {
                    return index;
                }
            }
            return -1;
        }

        @Override
        public int selectionForKey(char aKey, ComboBoxModel<?> model) {
            timeout.stop();
            pattern.append(Character.toLowerCase(aKey));
            String match = pattern.toString();
            for (int index = 0; index < model.getSize(); index++) {
                String text = model.getElementAt(index).toString().toLowerCase();
                if (text.startsWith(match)) {
                    timeout.start();
                    return index;
                }
            }

            timeout.start();
            return -1;
        }

    }

}

别忘了看看JComboBox#setKeySelectionManager,了解更多详细信息