越野车 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
了解更多详情
对于包含一些以重复字母开头的元素的 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
了解更多详情