有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

如果添加JButton,swing Java FocusListener和KeyListener将无法工作

我有两个实现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");
  }

}

共 (2) 个答案

  1. # 1 楼答案

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

    更好的方法(根据注释)是使用Key Bindings,如果使用正确的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());
        }
    }
    
  2. # 2 楼答案

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

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

    setFocusable(true);
    requestFocusInWindow();