Java: How to remove standard keys from any JComponent?

I want to control which keystroke belongs to Jcomponent . I even want to get how to remove the default keystrokes associated with Jcomponent and replace them with other favorite 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 does not work!

What I tried is to remove the SPACE key, which prevents the JComponent from responding to the SPACE clicks

I used this code to remove the SPACE key:

 firstButton.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "none"); 

The same for JComboBox

 sizesComboBox.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "none"); 

But it doesn’t work that it (JComboBox) is still responding to the SPACE key

For firstButton I removed the effect of pressing SPACE ; I added the F key, so now firstButton pressed, when you press the F key on the keyboard, ant does not respond to SPACE (assumed). Note that pressing F occurs even if firstButton has no focus ( JComponent.WHEN_IN_FOCUSED_WINDOW )

This is the SSCCE code showing my example:
Note. I intentionally did not add the line of code above to the second "secondButton" button, so it still responds 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 I want to control the default keystrokes for JComponent is because I want to remove the default SPACE effect for all JComponent, except for the one button that will respond to SPACE click wherever the focus is using JComponent.WHEN_IN_FOCUSED_WINDOW so that clicking another component (and moving the focus away from the button with the exception) does not interfere with the SPACE effect on this button.


Another point . If you checked the code above, you will notice that selecting an element from JComboBox creates two lines, if you select element "4", the output in JTextArea will be

 Item 4 Item 4 

Why two ??

Thanks.

+7
source share
1 answer

But it doesn’t work that he (JComboBox) still answers the SPACE key

You should use JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT InputMap in the same way (as you can see, I use KeyEvent and KeyStroke.getKeyStroke(int key,int modifier,boolean onRelease) as more readable and less error prone, i.e. entering an invalid string argument and t .d.):

 sizesComboBox.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) .put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0,false), "none"); 

The reason for this, as I understand it, is explained beautifully here :

A component contains (or is) a component that has focus. This input map is typically used for a composite component — a component whose implementation depends on child components. For example, JTable s do all their bindings with WHEN_ANCESTOR_OF_FOCUSED_COMPONENT , so if the user is editing, the up arrow (for example) still changes the selected cell.

So, the output of JCombobox is a composite component, and therefore we need the correct InputMap - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT to remove all its internal components. KeyBinding functionality for a particular ie SPACE key.

Another point: if you checked the code above, you will notice that selecting an element from JCombobox creates two lines, if you select element "4", the output in JTextArea is

 Item 4 Item 4 

Why two ??

As @mKorbel (+1 to his comment) said, there are 2 events that can happen:

  • item not selected
  • item selected

These events occur in pairs when we select a new value, which old is selected. Therefore, we must verify this and act accordingly:

 @Override public void itemStateChanged(ItemEvent e) { if(e.getStateChange()==ItemEvent.SELECTED) { //am item was selected do something } } 

Other offers:

  • Do not call setSize on a JFrame .

  • Use the appropriate LayoutManager and / or override getPreferredSize to return Dimension that match the contents and call pack() on the JFrame before the setting is visible even after the components are added.

+5
source

All Articles