Why can't I get KeyEvent.VK_TAB when I use Key Binding for a JPanel

会有一股神秘感。 提交于 2019-12-09 03:43:52

问题


I will print related info if users focus on current window and press a key. However, it works for some keys like 'a' but not for 'tab'. Here is a simple demo:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;


public class KeyBindingTest {
    public static void main(String[] args) {
        KeyBindingTest test = new KeyBindingTest();
        test.createUI();
    }

    public void createUI(){
        JFrame frame = new JFrame("KeyBinding Test");
        MainPanel mainPanel = new MainPanel();
        frame.add(mainPanel,BorderLayout.CENTER);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    @SuppressWarnings("serial")
    class MainPanel extends JPanel{
        public MainPanel(){
            setPreferredSize(new Dimension(200, 200));
            //========================key binding============================
            requestFocusInWindow();
            String aString = "aStr";
            getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), aString);
            getActionMap().put(aString, new AbstractAction() {          
                @Override
                public void actionPerformed(ActionEvent e) {
                    // TODO Auto-generated method stub
                    System.out.println("a is typed");
                }
            });     

            String tabString = "tabStr";
            getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), tabString);
            getActionMap().put(tabString, new AbstractAction() {            
                @Override
                public void actionPerformed(ActionEvent e) {
                    // TODO Auto-generated method stub
                    System.out.println("tab is typed");
                }
            });     
        }   
    }
}

What can I do to reach it? Thanks in advance.


回答1:


Quote from How to Use the Focus Subsystem (The Java™ Tutorials > Creating a GUI With JFC/Swing > Using Other Swing Features) (suggested by @alex2410(link to @camickr post) and @mKorbel):

In most Look and Feel models, components are navigated using the Tab and Shift-Tab keys. These keys are the default focus traversal keys and can be changed programmatically.
...
Tab shifts the focus in the forward direction. Shift-Tab moves the focus in the backward direction. Tabbing moves the focus through the buttons into the text area. Additional tabbing moves the cursor within the text area but not out of the text area because, inside a text area, Tab is not a focus traversal key. However, Control-Tab moves the focus out of the text area and into the first text field. Likewise, Control-Shift-Tab moves the focus out of the text area and into the previous component.
...
The Control key is used by convention to move the focus out of any component that treats Tab in a special way, such as JTable.
You have just received a brief introduction to the focus architecture. If you want more details, see the specification for the Focus Subsystem.

So if you want to make the Tab KeyBinding action work in the panel, you need to remove the Tab key focus navigation from the panel.

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

//http://stackoverflow.com/q/24800417/714968
public class KeyBindingTest3 {
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame("KeyBinding Test");
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new MainPanel());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}

class MainPanel extends JPanel {
  public MainPanel() {
    super();
    //@see JTable constructor
    Set<KeyStroke> forwardKeys = new HashSet<KeyStroke>(1);
    forwardKeys.add(KeyStroke.getKeyStroke(
        KeyEvent.VK_TAB, InputEvent.CTRL_MASK));
    setFocusTraversalKeys(
        KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardKeys);

    Set<KeyStroke> backwardKeys = new HashSet<KeyStroke>(1);
    backwardKeys.add(KeyStroke.getKeyStroke(
        KeyEvent.VK_TAB, InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK));
    setFocusTraversalKeys(
        KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backwardKeys);

    setPreferredSize(new Dimension(200, 200));

    String aString = "aStr";
    getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), aString);
    getActionMap().put(aString, new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        System.out.println("a is typed");
      }
    });
    String tabString = "TAB";
    getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
      KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), tabString);
    getActionMap().put(tabString, new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        System.out.println("tab is typed");
      }
    });
  }
}



回答2:


  • interesting issue with TAB, looks like as bug, because isn't possible to get, capture the KeyChar from TAB without using Shift_TAB before, event from TAB is somehow consumed elsewhere, no idea whats happened

  • my view - there is an issue with Focus because key TAB is used by Native OS and as built_in KeyBindings in Swing,

  • opposite issue with TAB and Shift_TAB in question Java Swing: how to stop unwanted shift-tab keystroke action

  • maybe someone has explanation how to catch a TAB event

  • TAB is used as KeyBindings (built_in in API) for many JComponents or navigations inside Container contains more than one JComponent

funny output from AWTEventListener (win8_64b/Java7_xxx)

     is typed //tab is pressed
     is typed
     is typed
     is typed
     is typed
     is typed
     is typed
     is typed
     is typed
 is typed //shift is pressed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
 is typed
     is typed // tab is pressed again
     is typed
     is typed
     is typed
 is typed //:-) nobody knows something from milky way
 is typed
     is typed
shift tab is typed //now is tab event unlocked for Container in Swing
shift tab is typed
shift tab is typed
ctrl tab is typed
ctrl tab is typed
ctrl tab is typed
tab is typed // now is possible, finally TAB is unlocked and firing an event
tab is typed
tab is typed

from code

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
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.JPanel;
import javax.swing.KeyStroke;

//https://stackoverflow.com/q/24800417/714968
public class KeyBindingTest {

    public static void main(String[] args) {
        KeyBindingTest test = new KeyBindingTest();
        test.createUI();
    }

    public void createUI() {
        JFrame frame = new JFrame("KeyBinding Test");
        MainPanel mainPanel = new MainPanel();
        frame.add(mainPanel, BorderLayout.CENTER);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
            @Override
            public void eventDispatched(AWTEvent event) {
                if (event instanceof KeyEvent) {
                    KeyEvent ke = (KeyEvent) event;
                    System.out.println(ke.getKeyChar() + " is typed");
                }
            }
        }, AWTEvent.KEY_EVENT_MASK);
    }

    @SuppressWarnings("serial")
    class MainPanel extends JPanel {

        public MainPanel() {
            setPreferredSize(new Dimension(200, 200));
            //========================key binding============================
            //requestFocusInWindow();
            String aString = "aStr";

            getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), aString);
            getActionMap().put(aString, new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // TODO Auto-generated method stub
                    System.out.println("a is typed");
                }
            });
            String tabString = "TAB";
            this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(tabString), tabString);
            //getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), tabString);
            this.getActionMap().put(tabString, new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // TODO Auto-generated method stub
                    System.out.println("tab is typed");
                }
            });
            String tabShiftString = "shift TAB";
            this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(tabShiftString), tabShiftString);
            //getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), tabString);
            this.getActionMap().put(tabShiftString, new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // TODO Auto-generated method stub
                    System.out.println("shift tab is typed");
                }
            });
            String ctrlShiftString = "ctrl TAB";
            this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(ctrlShiftString), ctrlShiftString);
            //getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), tabString);
            this.getActionMap().put(ctrlShiftString, new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // TODO Auto-generated method stub
                    System.out.println("ctrl tab is typed");
                }
            });
        }
    }
} 



回答3:


I think it should work if you put

setFocusTraversalKeysEnabled(false);

in your MainPanel constructor. At least it works for e.g. addKeyListener(...);



来源:https://stackoverflow.com/questions/24800417/why-cant-i-get-keyevent-vk-tab-when-i-use-key-binding-for-a-jpanel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!