使用键盘滚动弹出列表时,如何使JComboBox所选项目不被更改

我在面板中有一个JComboBox组件,并且附加了ItemListener。 但是每次上/下按键后都会被触发(当滚动打开弹出列表时)。 我想在用户接受选择后通过按Enter键来更改所选值。

使用鼠标时不是这种情况。 当我将鼠标移到combobox的列表上时,突出显示在鼠标指针之后,但是在我按下鼠标按钮之前,所选项目不会更改。 我希望键盘具有相同的行为,即通过向上/向下箭头移动高亮显示不会更改所选项目,但按Enter键可以。

我相信你应该能做到:

comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); 

在创建comboBox实例以获得此function之后

JComboBox.isTableCellEditor方法适用于通过列表的箭头移动,但不适用于KeySelectionManager支持的预先输入。 即,您仍然可以为用户键入的每个非导航键获取ActionEvents,因为JComboBox会解释这些字符,以便搜索模型以移动到(或接近)用户的预期选择。

这个解决方案有一个缺点,就是它改变了鼠标点击的动作命令,这对我来说是一个好的妥协,因为GUI的流程迫使用户将焦点从combobox改变

我最终创建了一个特殊的KeyListener,它依赖于将combobox的默认动作命令从comboBoxChanged更改为comboBoxMovement 。 这是我的combobox全部初始化后我需要的代码行:

 setExplicitSelectionManager(myComboBox); 

…这里是完成所有工作的方法及其包含的类:

 private void setExplicitSelectionManager(JComboBox comboBox) { class ExplicitSelectionManager implements KeyListener, FocusListener { private JComboBox src; private KeyListener superKeyListener; ExplicitSelectionManager(JComboBox src) { this.src = src; // we like what the default key listener does, but not the action command // it uses for ActionEvents it fires for plain text type-ahead characters this.superKeyListener = src.getKeyListeners()[0]; // we only have one src.removeKeyListener(superKeyListener); // will be replace right away, below } @Override public void keyTyped(KeyEvent e) { // basic combo box has no code in keyTyped } @Override public void keyPressed(KeyEvent e) { // in the default JComboBox implementation, the KeySelectionManager is // called from keyPressed. I'm fine with the implementation of // the default, but I don't want it firing ActionEvents that will cause // model updates src.setActionCommand("comboBoxMovement"); this.superKeyListener.keyPressed(e); src.setActionCommand("comboBoxChanged"); if (e.getKeyCode() == 10) { src.setSelectedIndex(src.getSelectedIndex()); } } @Override public void keyReleased(KeyEvent e) { // basic combo box has no code in keyReleased } @Override public void focusGained(FocusEvent e) { } @Override // this will also give us the event we want, if the user decides to Tab out of // the combo box, instead of hitting Enter public void focusLost(FocusEvent e) { src.setSelectedIndex(src.getSelectedIndex()); } } ExplicitSelectionManager newSelectionManager = new ExplicitSelectionManager(comboBox); comboBox.addKeyListener(newSelectionManager); comboBox.addFocusListener(newSelectionManager); } 

……这是动作执行方法

 private void comboBoxActionPerformed(java.awt.event.ActionEvent evt) { JComboBox source = (JComboBox) evt.getSource(); // "comboBoxChanged" is the default, // so any normal JComboBox can also use this action listener if (evt.getActionCommand().equals("comboBoxChanged")) { updateModel(source.getName(), (String) source.getSelectedItem()); } } 

在Java 8中,他们已经修复了这种行为,但只有在你设置了一个UI属性时才触发

 UIManager.getLookAndFeelDefaults().put("ComboBox.noActionOnKeyNavigation", true); 

它是ItemListener的预期行为。 每当显示的值发生更改时,都会触发事件。 根据您的要求,使用ActionListener