Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I registered an event at
JFrame
's root pane that reacts when hitting the space key (opens another window). I also have a
JTextField
inside that JFrame. When the users is in edit mode of my textfield and hits the space key, the space event should be consumed only by the textfield and not be forwarded to the
JFrame
's actionmap.
How do I do that?
Here is a runnable demo of the problem:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
public class TestDialog {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "spaceAction");
frame.getRootPane().getActionMap().put("spaceAction", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("spaceAction");
JTextField tf = new JTextField("textfield");
JLabel label = new JLabel("otherComponent");
label.setFocusable(true);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(tf);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
–
–
It's not a good idea to use space key as a global trigger. But if you really need it here is the way:
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.text.JTextComponent;
public class DialogTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "spaceAction");
frame.getRootPane().getActionMap().put("spaceAction", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
if (EventQueue.getCurrentEvent() instanceof KeyEvent) {
KeyEvent ke = (KeyEvent) EventQueue.getCurrentEvent();
if (!(ke.getComponent() instanceof JTextComponent)) {
System.out.println("spaceAction");
} else {
System.out.println("Ignore event in text component");
} else {
System.out.println("spaceAction");
JTextField tf = new JTextField("textfield");
JLabel label = new JLabel("otherComponent");
label.setFocusable(true);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(tf);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
Better way is to travers the component tree starting from the root pane and add the key binding only for the components you need (for example all labels). Here is my method for traversal
* Searches for all children of the given component which are instances of the given class.
* @param aRoot start object for search.
* @param aClass class to search.
* @param <E> class of component.
* @return list of all children of the given component which are instances of the given class. Never null.
public static <E> List<E> getAllChildrenOfClass(Container aRoot, Class<E> aClass) {
final List<E> result = new ArrayList<E>();
final Component[] children = aRoot.getComponents();
for (final Component c : children) {
if (aClass.isInstance(c)) {
result.add(aClass.cast(c));
if (c instanceof Container) {
result.addAll(getAllChildrenOfClass((Container) c, aClass));
return result;
–
–
I solved this by creating a simple JTextField subclass which consumes all the printable chars pressed by user. This way you don't have to modify an enclosing component.
public class JTextFieldNoKeyBinding extends JTextField
public JTextFieldNoKeyBinding()
// Key presses are processed by JTextField but NOT consumed,
// so they end up being also processed by the key binding framework.
// The only way to block them is to capture all the printable keys: see
// https://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html
for (char c = 32; c <= 126; c++)
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(c, 0), "doNothing");
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(c, InputEvent.SHIFT_DOWN_MASK), "doNothing");
getActionMap().put("doNothing", new NoAction());
private class NoAction extends AbstractAction
@Override
public void actionPerformed(ActionEvent e)
//do nothing
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.