You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java KeyBindings生效数秒后失效问题求助

解决KeyBindings生效数秒后失效的问题

我帮你找到了问题所在!你的KeyBindings失效的核心原因是输入映射的焦点依赖,结合你的代码,咱们一步步修复:

问题根源

你当前调用p.getInputMap()时,默认使用的是JComponent.WHEN_FOCUSED模式——这意味着只有当JPanelp获得焦点时,按键绑定才会触发。虽然你在初始化时调用了p.requestFocusInWindow(),但程序运行中焦点很容易意外转移(比如点击窗口空白区域、其他组件抢焦点),一旦JPanel失去焦点,所有按键绑定就会完全失效。

你提到尝试过WHEN_IN_FOCUSED_WINDOW但没效果,应该是调用方式不对,需要明确指定这个参数来获取对应的输入映射。

修复步骤

1. 修改输入映射的获取方式

在setupKeyBindings方法中,所有p.getInputMap()都要替换为p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW),这样按键绑定会绑定到窗口级别,只要窗口处于激活状态,不管哪个组件获得焦点,按键都会触发。

2. 移除不必要的焦点相关代码

既然用了窗口级别的输入映射,就不需要再依赖JPanel的焦点了,移除以下两行代码:

p.setFocusable(true);
p.requestFocusInWindow();

修改后的完整代码

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;

public class KeyBindingTest extends JFrame implements ActionListener {
    long counter = 0;
    int speed = 5;
    boolean isUp = false, isDown = false, isLeft = false, isRight = false;
    JLabel j = new JLabel();
    JPanel p = new JPanel();
    Timer t;

    Action upPressed = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("up on");
            isUp = true;
        }
    };

    Action upReleased = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            isUp = false;
            System.out.println("up off");
        }
    };

    Action downPressed = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("down on");
            isDown = true;
        }
    };

    Action downReleased = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            isDown = false;
            System.out.println("down off");
        }
    };

    Action leftPressed = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("left on");
            isLeft = true;
        }
    };

    Action leftReleased = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            isLeft = false;
            System.out.println("left off");
        }
    };

    Action rightPressed = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("right on");
            isRight = true;
        }
    };

    Action rightReleased = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            isRight = false;
            System.out.println("right off");
        }
    };

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    KeyBindingTest window = new KeyBindingTest();
                    window.run();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void run() {
        this.setBounds(640, 400, 640, 400);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        p.setBounds(0, 0, this.getWidth(), this.getHeight());
        p.setVisible(true);
        p.setBackground(Color.blue);
        p.setOpaque(true);
        p.setLayout(null);

        j.setBounds(320, 200, 10, 10);
        j.setVisible(true);
        j.setBackground(Color.red);
        j.setOpaque(true);

        this.add(p);
        p.add(j);

        setupKeyBindings();

        t = new Timer(1000 / 40, this);
        t.start();
    }

    private void setupKeyBindings() {
        // 明确使用窗口级别的输入映射
        p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "moveUp");
        p.getActionMap().put("moveUp", upPressed);
        p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"), "stopUp");
        p.getActionMap().put("stopUp", upReleased);

        p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "moveDown");
        p.getActionMap().put("moveDown", downPressed);
        p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released S"), "stopDown");
        p.getActionMap().put("stopDown", downReleased);

        p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "moveLeft");
        p.getActionMap().put("moveLeft", leftPressed);
        p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released A"), "stopLeft");
        p.getActionMap().put("stopLeft", leftReleased);

        p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "moveRight");
        p.getActionMap().put("moveRight", rightPressed);
        p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "stopRight");
        p.getActionMap().put("stopRight", rightReleased);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        counter++;
        System.out.println(counter);
        if (isUp) {
            j.setLocation(j.getX(), j.getY() - speed);
        }
        if (isDown) {
            j.setLocation(j.getX(), j.getY() + speed);
        }
        if (isLeft) {
            j.setLocation(j.getX() - speed, j.getY());
        }
        if (isRight) {
            j.setLocation(j.getX() + speed, j.getY());
        }
        repaint();
    }
}

额外优化建议

你可以把重复的按键绑定逻辑抽成一个工具方法,减少代码冗余,比如:

private void bindKey(String key, String pressedActionKey, Action pressedAction, String releasedActionKey, Action releasedAction) {
    p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(key), pressedActionKey);
    p.getActionMap().put(pressedActionKey, pressedAction);
    p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released " + key), releasedActionKey);
    p.getActionMap().put(releasedActionKey, releasedAction);
}

然后在setupKeyBindings里直接调用:

bindKey("W", "moveUp", upPressed, "stopUp", upReleased);
bindKey("S", "moveDown", downPressed, "stopDown", downReleased);
// ... 其他方向键同理

内容的提问来源于stack exchange,提问作者iopener

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:12:58