Как сделать выбранный элемент JComboBox не изменен при прокрутке его всплывающего списка с помощью клавиатуры

У меня есть компонент JComboBox на панели и ItemListener, прикрепленный к нему. Но он запускается после каждого нажатия клавиши вверх/вниз (при прокрутке, хотя открыт всплывающий список). Я хочу изменить выбранное значение после того, как пользователь примет выбор, нажав, например, клавишу Enter.

Это не относится к использованию мыши. Когда я перемещаю мышь над списком combobox, подсветка следует указателю мыши, но выбранный элемент не изменяется до тех пор, пока я не нажму кнопку мыши. Я хотел бы иметь такое же поведение для клавиатуры, т.е. Перемещение выделения с помощью стрелки вверх/вниз не изменяет выбранный элемент, но нажатие Enter делает.

Ответ 1

Я считаю, что вы должны это сделать:

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

после того, как вы создали экземпляр comboBox для получить эту функциональность

Ответ 2

Метод JComboBox.isTableCellEditor работает для перемещения по стрелке через список, но не работает для ввода типа, поддерживаемого KeySelectionManager. то есть вы все равно получаете ActionEvents для каждого неавигационного ключа, который пользователь вводит, поскольку JComboBox интерпретирует эти символы для поиска, хотя модель перемещается (или приближается к) для выбора пользователя.

это решение имеет недостаток в том, что он изменяет команду действий для щелчков мыши, что для меня было компромиссом OK, потому что поток 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

В Java 8 они исправили это поведение, но только триггер, если u установил одно свойство пользовательского интерфейса

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

Ответ 4

Его ожидаемое поведение с ItemListener. всякий раз, когда отображаемое значение меняет событие. Для вашего требования используйте ActionListener.