如何消除keyPress的延迟?

时间:2014-07-21 02:28:22

标签: java swing awt keylistener

所以我已经看到了一些关于这个的线程,我需要一些关于如何具体修复它的帮助。当您按住某个键时,Java将读取第一个按键,然后会有一个小的延迟,然后它将持续读取按键,直到您释放该键。

public void keyPressed(KeyEvent key) {
    int code = key.getKeyCode();
    if (code == KeyEvent.VK_DOWN) {
        //Do stuff
    }
    if (code == KeyEvent.VK_LEFT) {
        //Do stuff
    }
    if (code == KeyEvent.VK_RIGHT) {
        //Do stuff
    }
    if (code == KeyEvent.VK_UP) {
        //Do stuff
    }
}

这是我目前的代码。我听说要解决这个问题,你可以创建一个快速检查按键的计时器,但我不确定如何做到这一点。会在这里感谢一些帮助,或者是否有更好的解决方案。

1 个答案:

答案 0 :(得分:3)

您的问题的基本答案是,您不能,延迟是特定于操作系统的。

答案越长,您应该忽略各个事件本身,并通过使用适当的标志来监控状态的变化(在按下和释放之间)。

这意味着,当按下某个键时,您设置一些标志,您可以使用该标志来更改程序的状态,并在释放时重置它。

这解除了事件与状态变化的关联,并为您提供了更多的灵活性,因为您的程序并不关心导致状态变化的原因,只是状态已经发生变化并且应该对其做出反应。

这将要求你有某种"循环"它的责任在于监控这一变化并对其做出相应的反应。在游戏中,这通常被称为游戏循环",但也可称为"主循环"。

这是"循环"有责任更新程序的状态并绘制它。

下面是一个非常简单的示例,它使用key bindings APIjavax.swing.Timer来演示基本概念

import com.sun.glass.events.KeyEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MoveMe {

    public static void main(String[] args) {
        new MoveMe();
    }

    public MoveMe() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MovementState {

        public int xDirection;
        public int yDirection;

    }

    public class TestPane extends JPanel {

        private MovementState movementState;
        private Rectangle box;

        public TestPane() {
            movementState = new MovementState();
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "down-pressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "down-released");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "up-pressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "up-released");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "left-pressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "left-released");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "right-pressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "right-released");

            am.put("down-pressed", new YDirectionAction(movementState, 2));
            am.put("down-released", new YDirectionAction(movementState, 0));
            am.put("up-pressed", new YDirectionAction(movementState, -2));
            am.put("up-released", new YDirectionAction(movementState, 0));
            am.put("left-pressed", new XDirectionAction(movementState, -2));
            am.put("left-released", new XDirectionAction(movementState, 0));
            am.put("right-pressed", new XDirectionAction(movementState, 2));
            am.put("right-released", new XDirectionAction(movementState, 0));

            box = new Rectangle(90, 90, 20, 20);

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    box.x += movementState.xDirection;
                    box.y += movementState.yDirection;
                    if (box.x < 0) {
                        box.x = 0;
                    } else if (box.x + box.width > getWidth()) {
                        box.x = getWidth() - box.width;
                    }
                    if (box.y < 0) {
                        box.y = 0;
                    } else if (box.y + box.height > getHeight()) {
                        box.y = getHeight() - box.height;
                    }
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            g2d.fill(box);
            g2d.dispose();
        }
    }

    public abstract class AbstractDirectionAction extends AbstractAction {

        private final MovementState movementState;
        private final int value;

        public AbstractDirectionAction(MovementState movementState, int value) {
            this.movementState = movementState;
            this.value = value;
        }

        public MovementState getMovementState() {
            return movementState;
        }

        public int getValue() {
            return value;
        }

    }

    public class YDirectionAction extends AbstractDirectionAction {

        public YDirectionAction(MovementState movementState, int value) {
            super(movementState, value);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            getMovementState().yDirection = getValue();
        }

    }

    public class XDirectionAction extends AbstractDirectionAction {

        public XDirectionAction(MovementState movementState, int value) {
            super(movementState, value);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            getMovementState().xDirection = getValue();
        }

    }

}