Java FocusListener和KeyListener don';如果我添加一个JButton,它将无法工作

Java FocusListener和KeyListener don';如果我添加一个JButton,它将无法工作,java,swing,Java,Swing,我有两个实现KeyListener和FocusListener接口的类。两者都不起作用,但如果我不通过注释或删除以下内容来添加JButton:add(whiteJButton),那么它们就起作用了。有人能给我解释一下为什么会这样吗?提前谢谢 import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent;

我有两个实现KeyListener和FocusListener接口的类。两者都不起作用,但如果我不通过注释或删除以下内容来添加JButton:
add(whiteJButton)
,那么它们就起作用了。有人能给我解释一下为什么会这样吗?提前谢谢

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class JFrames {

  public static void main(String[] args) {

    JFrame myJFrame = new JFrame("MyJFrame");

    myJFrame.setBounds(400, 400, 500, 500);
    myJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    MyJPanel myJPanel = new MyJPanel();
    myJFrame.add(myJPanel);

    // Doesn't work
    myJFrame.addKeyListener(new MyKeyListener());
    // Doesn't work
    myJFrame.addFocusListener(new MyFocusListener());

    myJFrame.setVisible(true);
  }

  static class MyJPanel extends JPanel {

    public MyJPanel() {

      JButton whiteJButton = new JButton("WHITE");
      add(whiteJButton);
      whiteJButton.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
          setBackground(Color.WHITE);
        }
      });
    }
  }
}

class MyKeyListener implements KeyListener {

  @Override
  public void keyTyped(KeyEvent e) {
    System.out.println("keyTyped: " + e.getKeyChar());
  }

  @Override
  public void keyPressed(KeyEvent e) {
    System.out.println("keyPressed: " + e.getKeyChar());
  }

  @Override
  public void keyReleased(KeyEvent e) {
    System.out.println("keyReleased: " + e.getKeyChar());
  }

}

class MyFocusListener implements FocusListener {

  @Override
  public void focusGained(FocusEvent e) {
    System.out.println("focusGained");
  }

  @Override
  public void focusLost(FocusEvent e) {
    System.out.println("focusLost");
  }

}

您必须聚焦添加侦听器的对象,尝试将侦听器添加到“myJFrame”。你不能专注于杰帕内尔

您的JPanel可能在开始时不可聚焦,而您的JButton获得了焦点。 因此,您还可以将这些代码添加到“myJPanel”:


问题是该按钮从JFrame窃取焦点,从而阻止焦点侦听器工作(焦点已经消失)。如果您确实需要使用KeyListener,那么一些解决方案是很麻烦的,包括使JButton不可聚焦:
whiteJButton.setFocusable(false),但如果执行此操作,则需要对添加的所有组件执行此操作。是的,您可以按照另一个答案的建议请求焦点,但应该是
requestFocusInWindw()
,而不是
requestFocus()
(许多类似的问题解释了为什么会这样)。如果你这样做了,组件仍然是可聚焦的,那么如果组件获得了聚焦,整个事情就会崩溃——不好

更好的方法(根据注释)是使用正确的InputMap,而不需要焦点。请注意,键绑定是Swing本身为组件捕获击键的方式,所以在Swing通用结构和契约中使用键绑定。密钥绑定的问题是,您必须绑定希望捕获的每个密钥,但您可以使用for循环来帮助实现这一点

另一种解决方案是将KeyEventDispatcher用于键盘焦点管理器:

KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
      @Override
      public boolean dispatchKeyEvent(KeyEvent e) {
        // code goes here
        return false;
      }
});
使用键绑定的示例:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class KeyboardFun extends JPanel {
    private InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
    private ActionMap actionMap = getActionMap();

    public KeyboardFun() {
        setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
        setLayout(new GridLayout(0, 8, 3, 3));
        for (char c = 'A'; c <= 'Z'; c++) {
            final String text = String.valueOf(c);
            JButton button = new JButton(text);
            button.addActionListener(e -> {System.out.println("Key pressed: " + text);});
            add(button);
            setBinding(c, button);
        }
    }

    private void setBinding(char c, final JButton button) {
        KeyStroke keyStroke = KeyStroke.getKeyStroke(Character.toLowerCase(c));
        inputMap.put(keyStroke, keyStroke.toString());
        actionMap.put(keyStroke.toString(), new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                button.doClick();
            }
        });
    }

    private static void createAndShowGui() {
        KeyboardFun mainPanel = new KeyboardFun();

        JFrame frame = new JFrame("KeyboardFun");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}
导入java.awt.GridLayout;
导入java.awt.event.ActionEvent;
导入javax.swing.*;
@抑制警告(“串行”)
公共类键盘趣味扩展JPanel{
私有InputMap InputMap=getInputMap(在聚焦窗口中时);
私有ActionMap ActionMap=getActionMap();
公共键盘乐趣(){
setBorder(BorderFactory.createEmptyByOrder(3,3,3,3));
setLayout(新的GridLayout(0,8,3,3));
for(charc='A';c{System.out.println(“按键:+text);});
添加(按钮);
立根(c,按钮);
}
}
私有无效设置绑定(字符c,最终JButton按钮){
击键击键=击键.getKeyStroke(Character.toLowerCase(c));
inputMap.put(击键,击键.toString());
actionMap.put(keyStroke.toString(),new AbstractAction()){
@凌驾
已执行的公共无效操作(操作事件e){
button.doClick();
}
});
}
私有静态void createAndShowGui(){
KeyboardFun主面板=新KeyboardFun();
JFrame=新的JFrame(“KeyboardFun”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(主面板);
frame.pack();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
公共静态void main(字符串[]args){
调用器(()->createAndShowGui());
}
}

还有另一个不使用KeyListener的原因,而应该选择支持。请看这里的问题是JButton从一开始就抓住了焦点,阻止了keystener工作(因为它需要焦点才能工作)。一个更大的问题是您的KeyListener最初的用途是什么,您是否可以重新调整代码的用途以使用密钥绑定?谢谢。它快把我逼疯了。很好的解释!
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class KeyboardFun extends JPanel {
    private InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
    private ActionMap actionMap = getActionMap();

    public KeyboardFun() {
        setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
        setLayout(new GridLayout(0, 8, 3, 3));
        for (char c = 'A'; c <= 'Z'; c++) {
            final String text = String.valueOf(c);
            JButton button = new JButton(text);
            button.addActionListener(e -> {System.out.println("Key pressed: " + text);});
            add(button);
            setBinding(c, button);
        }
    }

    private void setBinding(char c, final JButton button) {
        KeyStroke keyStroke = KeyStroke.getKeyStroke(Character.toLowerCase(c));
        inputMap.put(keyStroke, keyStroke.toString());
        actionMap.put(keyStroke.toString(), new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                button.doClick();
            }
        });
    }

    private static void createAndShowGui() {
        KeyboardFun mainPanel = new KeyboardFun();

        JFrame frame = new JFrame("KeyboardFun");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}