越野车 JCombobox - KeyPressed

Buggy JCombobox - KeyPressed

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

有没有办法解决这个问题,让双键真正return输入什么?

快速示例程序:

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

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

默认实现做的一件事是,它会根据项目的第一个字符尝试查找与击键匹配的项目(当通过 toString 转换为 String 时). "neat" 的事情是,它将从当前 selected 项开始搜索(如果不是 null),如果找不到另一个匹配项,它将从头开始搜索取而代之的是模型。

这意味着,如果您重复输入 3,它将逐步遍历所有以 3 开头的项目。 (30, 31, 32 ... 39, 300 ...)

但是,这显然不是您想要的,因此,您必须提供自己的算法。

一个非常重要的考虑是,当用户停止输入时会发生什么?如果用户输入 33,停止,然后再次输入 3,会发生什么?应该 select 3 还是 333?

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

当被 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 了解更多详情