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

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

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

4 ответов


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

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

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


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

это решение имеет недостаток в том, что оно изменяет команду действия для щелчков мыши, что было для меня компромиссом OK потому что поток GUI заставляет пользователя изменить фокус от поля со списком

Я закончил тем, что сделал специальный KeyListener, который relys при изменении команды действия по умолчанию в поле со списком из 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());
    }
}                                               

в Java 8 они исправили это поведение, но только запускают, если U установил одно свойство UI

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

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