问题
I want to control which keystroke belong to which Jcomponent
. I even want to get how to remove the default keystrokes associated with a Jcomponent
and replace them with other favourite keystrokes.
I followed this oracle tutorial, it gives an example with JButton, I tried it and it works fine, but when I try it with JComboBox it doesn’t work!
What exactly I tried is removing the SPACE key, that is prevent the JComponent from responding to SPACE presses
I used this code to remove the SPACE key:
firstButton.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "none");
The same thing for JComboBox
sizesComboBox.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "none");
But doesn’t work, that it is (JComboBox) still respond to the SPACE key
For the firstButton
that I removed the effect of SPACE presses; I added the key F, So that now the firstButton
is pressed when you press the F key on the keyboard, ant not respond to SPACE (intended). Note that presses of F take place even if firstButton
doesn’t have the focus (JComponent.WHEN_IN_FOCUSED_WINDOW
)
This is a SSCCE code showing my example:
Note: I intentionally didn’t add the line of code above to the second button "secondButton" so it is still respond to SPACE by default.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.*;
public class KeyStrokeTest extends JPanel
{
JPanel widgetPanel;
JPanel textAreaPanel;
JButton firstButton;
JButton secondButton;
JTextArea textArea;
JComboBox<Integer> sizesComboBox;
public KeyStrokeTest()
{
firstButton = new JButton("First");
firstButton.addActionListener(eventWatcher);
firstButton.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "none");
firstButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F"), "F Key");
firstButton.getActionMap().put("F Key", eventWatcher);
secondButton = new JButton("Second");
secondButton.addActionListener(eventWatcher);
sizesComboBox = new JComboBox<>();
sizesComboBox.addItemListener(new itemListenerClass());
for (int i = 1; i <= 8; i++)
{
sizesComboBox.addItem(i);
}
sizesComboBox.setSelectedIndex(0);
sizesComboBox.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "none");
textArea = new JTextArea(0, 0);
JScrollPane scrollTextArea = new JScrollPane(textArea);
scrollTextArea.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
textArea.setEditable(false);
widgetPanel = new JPanel();
textAreaPanel = new JPanel(new BorderLayout());
widgetPanel.add(firstButton);
widgetPanel.add(secondButton);
widgetPanel.add(sizesComboBox);
textAreaPanel.add(scrollTextArea, BorderLayout.CENTER);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, textAreaPanel, widgetPanel);
splitPane.setDividerLocation(280);
splitPane.setResizeWeight(.5d);
this.setLayout(new BorderLayout());
this.add(splitPane);
}
AbstractAction eventWatcher = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent ae)
{
Object source = ae.getSource();
if (source == firstButton)
{
textArea.append("First button clicked\n");
}
if (source == secondButton)
{
textArea.append("Second button clicked\n");
}
}
};
private class itemListenerClass implements ItemListener
{
@Override
public void itemStateChanged(ItemEvent e)
{
if (e.getSource() == sizesComboBox)
{
if (textArea != null)
{
textArea.append("Item " + sizesComboBox.getSelectedItem() + "\n");
}
}
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("KeyStroke Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 300);
frame.add(new KeyStrokeTest(), BorderLayout.CENTER);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
The reason why I want to control over default keystrokes for JComponent is because I want to remove the default effect of SPACE on all the JComponent, except one button that will respond to the SPACE presses, wherever the focus is on, using JComponent.WHEN_IN_FOCUSED_WINDOW
, so that clicking another component (and moving the focus away from the excepted button) will not prevent the effect of SPACE on that button.
Another point: If you tested the code above, you will notice that selecting an item from the JComboBox poduces two lines of, if you select item "4" the output in the JTextArea is
Item 4 Item 4
Why two??
Thanks.
回答1:
But doesn't work, that it is (JComboBox) still respond to the SPACE key
You should use the JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
InputMap
like so (As you may notice I make use of KeyEvent
and KeyStroke.getKeyStroke(int key,int modifier,boolean onRelease)
as its more readable and less prone to mistakes i.e typing the wrong string argument etc.):
sizesComboBox.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0,false), "none");
The reason for this as far as I see is explained nicely here:
The component contains (or is) the component that has the focus. This input map is commonly used for a composite component — a component whose implementation depends on child components. For example,
JTable
s make all their bindings usingWHEN_ANCESTOR_OF_FOCUSED_COMPONENT
so that if the user is editing, the up-arrow key (for example) still changes the selected cell.
So I deduce JCombobox
is a composite component and thus we need the correct InputMap
- WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
, to remove all its inner components KeyBinding functionality for a specific key i.e SPACE.
Another point: If you tested the code above, you will notice that selecting an item from the
JComboBox
poduces two lines of, if you select item "4" the output in theJTextArea
isItem 4 Item 4
Why two??
As said by @mKorbel (+1 to his comment) there are 2 events which can occur:
- an item is deselected
- an item is selected
These events, occur in pairs as when we select a new value the old one is deselected. Thus we must check for this and act appropriately:
@Override
public void itemStateChanged(ItemEvent e)
{
if(e.getStateChange()==ItemEvent.SELECTED) {
//am item was selected do something
}
}
Other suggestions:
Dont call
setSize
onJFrame
.Use an appropriate
LayoutManager
and/or overridegetPreferredSize
to returnDimension
s which fit the contents and callpack()
onJFrame
before setting is visible and after adding components.
来源:https://stackoverflow.com/questions/14546174/java-how-to-remove-default-keystrokes-from-any-jcomponent