How to make JComboBox selected item not changed when scrolling through its popuplist using keyboard
I have a JComboBox component in the panel and ItemListener attached to it. But it gets fired after every up/down keypress (when scrolling though opened popup list). I want to change the selected value after the user accepts selection by pressing for example Enter key.
This is not a case when using mouse. When I move mouse over the combobox's list the h开发者_如何学Pythonighlight follows mouse pointer, but selected item is not changed until I press the mouse button. I would like to have the same behavior for keyboard, i.e. moving highlight via up/down arrow does not change selected item, but pressing Enter does.
I believe you should be able to do:
comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
after you have created your comboBox
instance to get this functionality
In Java 8 they have fixed this behaviour, but only trigger if u set one UI property
UIManager.getLookAndFeelDefaults().put("ComboBox.noActionOnKeyNavigation", true);
the JComboBox.isTableCellEditor
method works for arrow movement through the list, but does not work for type-ahead supported by the KeySelectionManager. i.e. you still get ActionEvents for every non-navigation key the user types, as the JComboBox interprets those characters for searching though the model to move to (or move close to) the user's intended selection.
this solution has a drawback in that it changes the action command for mouse clicks, which was a OK compromise for me because the the flow of the GUI forces the user to change the focus away from the combo box
I ended up making a special KeyListener, that relys on changing the combo box's default action command from comboBoxChanged
to comboBoxMovement
. Here's the line of code I need after my combo box is all initialized:
setExplicitSelectionManager(myComboBox);
... and here is the method and its contained class that do all the work:
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);
}
... and here's the action performed method
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());
}
}
Its the expected behavior with the ItemListener
. whenever the displayed value changes the event is fired. For your requirement use an ActionListener
.
精彩评论