添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
失落的饭卡  ·  uniapp得到base64 - CSDN文库·  2 月前    · 
无邪的弓箭  ·  深入理解 Java 中的 ...·  4 月前    · 
至今单身的牛排  ·  Oops!!! - 简书·  11 月前    · 
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);
                What InputMap level did you use? Maybe consider providing a runnable example which demonstrates your problem
– MadProgrammer
                Apr 14, 2016 at 8:30
                I tried all 3 InputMap levels, they are working as expected (ancestor_of_focussed_comp, when_in_focussed_window, when_focussed), the first two are working as I described, the 3rd level doesnt work at all, since the root pane cannot have the focus and should not
– trainrobbery
                Apr 14, 2016 at 8:50

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 it using your first solution, thank you. But is this a feature or is it a bug that JTextField forwards already consumed keyboard characters? – trainrobbery Apr 14, 2016 at 11:19 @trainrobbery I think it's a feature. In some cases multiple event processing could be necessary. – Sergiy Medvynskyy Apr 14, 2016 at 11:44

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.