MainPanel 没有在嵌套的 JPanel 中监听 KeyBinding

MainPanel not listening to KeyBinding inside nested JPanel

我有一个 JFrame,它上面有一个扩展 JPanel 的 MainPanel。 MainPanel 包含另外 2 个使用 BorderLayout 排列视图的 JPanel。

其中一个面板包含触发点击事件的按钮。 但是对于另一个面板,键绑定根本不会被触发。

这是包含 2 个面板的 MainClass 的代码

public class MainClass implements ... {

    public JFrame frame;
    JPanel highscore;
    Board board;
    Board.MoveAction moveAction;

    @Override
    public void init(Platform platform, int id) {
        this.platform = platform;
        this.selfId = id;

        platform.setAbout("Hello ");
        //platform.setSleepAfterSync(sleepPeriod);

        frame = platform.createWindow(false);

        // Create mainPanel to add all nested panels and buttons inside
        JPanel mainPanel = new MainPanel();
        mainPanel.add(board, BorderLayout.CENTER);
        mainPanel.add(highscore, BorderLayout.PAGE_END);
        frame.add(mainPanel);

        frame.setTitle("Test");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(380, 440);
        //frame.setBackground(Color.YELLOW);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }


public class MainPanel extends JPanel {

    public MainPanel() {
        setLayout(new BorderLayout());
        //setBackground(Color.RED);

        <-- the board here is the issue in the mainpanel-->
        board = new Board(platform);
        //board.setBackground(Color.BLUE);


        highscore = new JPanel();
        JButton button = new JButton("highscore");
        button.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.print("highscore button");
            }
        });
        highscore.add(button);
        //highscore.setBackground(Color.GREEN);
    }
}

这里是 Board class 的代码,它扩展了 JPanel

public class Board extends JPanel implements ActionListener {

    public Platform platform;
    private int req_dx, req_dy, view_dx, view_dy;
    private int IFW = JComponent.WHEN_IN_FOCUSED_WINDOW;
    private final String MOVE_UP = "UP";
    private final String MOVE_DOWN = "DOWN";
    private final String MOVE_RIGHT = "RIGHT";
    private final String MOVE_LEFT = "LEFT";
    private final String START_GAME = "START";

    public Board(Platform platform) {

        this.platform = platform;
        loadImages();
        initVariables();
        initBoard();
        initKeyBinding();
    }

    private void initBoard() {
        setBackground(Color.black);
        setDoubleBuffered(true);
    }

    private void initVariables() {
    ...
    ...

    }

    ..
    ..
    ..
    ..

     public void initKeyBinding() {

        System.out.println("HERE?  init key binding -> yep ");

        addKeyBinding(MOVE_UP, KeyEvent.VK_UP, new MoveAction(MOVE_UP, 0,-1));
        addKeyBinding(MOVE_DOWN, KeyEvent.VK_DOWN, new MoveAction(MOVE_DOWN, 0,1));
        addKeyBinding(MOVE_LEFT, KeyEvent.VK_LEFT, new MoveAction(MOVE_LEFT, -1 ,0));
        addKeyBinding(MOVE_RIGHT, KeyEvent.VK_RIGHT, new MoveAction(MOVE_RIGHT, 1,0));

        //this 's' to start is definitely wrong
        //figure out how to change from if (key == 's' || key == 'S') to keybinding
        //addKeyBinding(START_GAME, KeyEvent.VK_S, new MoveAction(START_GAME, KeyEvent.VK_S, KeyEvent.VK_S));
}


    private void addKeyBinding(String name, int keyCode, AbstractAction action) {
        //on keyRelease - true if the KeyStroke should represent a key release; false otherwise
        // keyCode - an int specifying the numeric code for a keyboard key
        // ie getInputMap(IFW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true/false), MOVE_UP);

        getInputMap(IFW).put(KeyStroke.getKeyStroke(keyCode, 0), name);
        getActionMap().put(keyCode, action);
}


    public class MoveAction extends AbstractAction {

        private int deltaX;
        private int deltaY;
        private String direction;

        public MoveAction(String direction, int deltaX, int deltaY) {
            this.direction = direction;
            this.deltaX = deltaX;
            this.deltaY = deltaY;
        }

        @Override
        public void actionPerformed(ActionEvent e) {

            System.out.print(direction);


            switch (direction) {
                case MOVE_UP:
                    System.out.println("up? ");
                    req_dx = 0;
                    req_dy = -1;
                    // do stuff that will move up
                case MOVE_DOWN:
                    System.out.println("down? ");
                    req_dx = 0;
                    req_dy = 1;
                    // do stuff that will move down
               // case START_GAME:
               //     System.out.println("sss");
               //     inGame = true;
               //     initGame();

            }
        }
    }
}

我知道 KeyBinding 有 4 个组件需要注意

一个动作,即 actionPerformed {.. }

一个击键即(KeyStroke.getKeyStroke..)

一个 InputMap 即 getInputMap(...)

一个 ActionMap 即 getActionMap(...)

在 MainPanel 中触发我的键盘事件我错过了什么?谢谢!

以此为参考 设法将按键侦听器更改为按键绑定

  public void initKeyBinding() {

    mapKeys = new HashMap<>();
    mapKeys.put(MOVE_UP, false);
    mapKeys.put(MOVE_DOWN, false);
    mapKeys.put(MOVE_LEFT, false);
    mapKeys.put(MOVE_RIGHT, false);
    mapKeys.put(START_GAME, false);
    mapKeys.put(PAUSE_GAME, false);
    mapKeys.put(ESCAPE, false);

    addKeyBinding(KeyEvent.VK_UP, MOVE_UP);
    addKeyBinding(KeyEvent.VK_DOWN, MOVE_DOWN);
    addKeyBinding(KeyEvent.VK_LEFT, MOVE_LEFT);
    addKeyBinding(KeyEvent.VK_RIGHT, MOVE_RIGHT);
    addKeyBinding(KeyEvent.VK_S, START_GAME);
    addKeyBinding(KeyEvent.VK_ESCAPE, ESCAPE);

}

private void addKeyBinding(int keyCode, String name) {
    // keyRelease - true if the KeyStroke should represent a key release; false otherwise
    // keyCode - an int specifying the numeric code for a keyboard key

    InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
    ActionMap actionMap = getActionMap();

    inputMap.put(KeyStroke.getKeyStroke(keyCode, 0, true), "pressed" + name);
    inputMap.put(KeyStroke.getKeyStroke(keyCode, 0, false), "released" + name);

    actionMap.put("pressed" + name, new KeyAction(name, true));
    actionMap.put("released" + name, new KeyAction(name, false));
}


public class KeyAction extends AbstractAction {
    private String name;
    private boolean state;

    public KeyAction(String name, boolean state) {
        this.name = name;
        this.state = state;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println(name);
        System.out.println(state);
        mapKeys.put(name, state);

        if (inGame) {
            switch (name) {
                case MOVE_UP:
                    req_dx = 0;
                    req_dy = -1;
                    break;
                case MOVE_DOWN:
                    req_dx = 0;
                    req_dy = 1;
                    break;
                case MOVE_RIGHT:
                    req_dx = 1;
                    req_dy = 0;
                    break;
                case MOVE_LEFT:
                    req_dx = -1;
                    req_dy = 0;
                    break;
                case ESCAPE:
                    if (timer.isRunning()) {
                        inGame = false;
                    }
                    break;
            }
        } else {
            if (mapKeys.put(START_GAME, false)) {
                inGame = true;
                initGame();
            }
        }
    }
}

@Override
public void actionPerformed(ActionEvent e) {

    repaint();
}