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

时间:2011-03-04 14:08:14

标签: java swing keyboard properties jcombobox

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

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

4 个答案:

答案 0 :(得分:19)

我相信你应该能够做到:

comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
comboBox实例创建为get this functionality

答案 1 :(得分:2)

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

时才触发
UIManager.getLookAndFeelDefaults().put("ComboBox.noActionOnKeyNavigation", true);

答案 2 :(得分:1)

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

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

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

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

答案 3 :(得分:0)

它与ItemListener的预期行为。只要显示的值发生更改,就会触发事件。根据您的要求,使用ActionListener