使用键盘滚动弹出列表时,如何使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
。