使用KeyAdapter的简单程序在按下几个键后无法注册单个键。 代码解决方案

在简单的绘图程序中,我只是想把基础知识搞定。 我有一个绘制矩形的程序,然后让我向任何方向移动它。 我使用一个线程来顺利行动。 然而,让我感到困扰的是,如果我按下三个键并释放其中两个键,程序将不会检测到第三个键,从而使矩形保持静止。

我在这里要求太多,还是硬件相关? 我有一个非常便宜的键盘。

如果您想乘车,这是完整的计划。

import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class Boxxy extends JFrame implements Runnable{ int xPos, yPos, xDir, yDir; MyPanel panel; ImageIcon ii; Image i; public Boxxy() { setSize(400,400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); panel = new MyPanel(); add(panel); setVisible(true); } class MyPanel extends JPanel { private static final long serialVersionUID = 1L; private int squareX = 0; private int squareY = 0; private int squareW = 20; private int squareH = 20; private MyPanel() { setFocusable(true); addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case (KeyEvent.VK_UP): setyDir(-1); break; case (KeyEvent.VK_DOWN): setyDir(1); break; case (KeyEvent.VK_LEFT): setxDir(-1); break; case (KeyEvent.VK_RIGHT): setxDir(1); break; } } public void keyReleased(KeyEvent e) { switch (e.getKeyCode()) { case (KeyEvent.VK_UP): setyDir(0); break; case (KeyEvent.VK_DOWN): setyDir(0); break; case (KeyEvent.VK_LEFT): setxDir(0); break; case (KeyEvent.VK_RIGHT): setxDir(0); break; } } }); } private void repaintSquare(int x, int y) { int OFFSET = 1; if ((squareX!=x) || (squareY!=y)) { repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET); squareX=x; squareY=y; repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET); } } protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.RED); g.fillRect(squareX,squareY,squareW,squareH); } } private void move() { panel.repaintSquare(xPos, yPos); xPos += xDir; yPos += yDir; } private void setxDir(int x) { this.xDir = x; } private void setyDir(int y) { this.yDir = y; } public static void main(String[] args) { Thread t = new Thread(new Boxxy()); t.start(); } @Override public void run() { try { while(true) { move(); Thread.sleep(5); } } catch (InterruptedException e) { e.printStackTrace(); } } } 

正如在类似问题中所讨论的那样,不要使用KeyListener,而是使用Key Bindings。 Swing Timer可用于重复移动精灵。


编辑
例如:

 import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.*; import java.util.EnumMap; import javax.swing.*; @SuppressWarnings("serial") public class Boxxy2 extends JPanel { private static final int PREF_W = 400; private static final int PREF_H = PREF_W; private static final int SQUARE_W = 20; private static final String PRESSED = "pressed"; private static final String RELEASED = "released"; public static final int MOVE_SCALE = 1; private static final int TIMER_DELAY = 5; private int squareX = 0; private int squareY = 0; private int squareW = SQUARE_W; private int squareH = SQUARE_W; private EnumMap dirMap = new EnumMap<>(Direction.class); public Boxxy2() { setupKeyBinding(); new Timer(TIMER_DELAY, new TimerListener()).start(); } private void setupKeyBinding() { int condition = JComponent.WHEN_IN_FOCUSED_WINDOW; InputMap inMap = getInputMap(condition); ActionMap actMap = getActionMap(); // this uses an enum of Direction that holds ints for the arrow keys for (Direction direction : Direction.values()) { dirMap.put(direction, Boolean.FALSE); int key = direction.getKey(); String name = direction.name(); KeyStroke keyPressed = KeyStroke.getKeyStroke(key, 0, false); KeyStroke keyReleased = KeyStroke.getKeyStroke(key, 0, true); // add the key bindings for arrow key and shift-arrow key inMap.put(keyPressed, name + PRESSED); inMap.put(keyReleased, name + RELEASED); actMap.put(name + PRESSED, new MyKeyAction(this, direction, true)); actMap.put(name + RELEASED, new MyKeyAction(this, direction, false)); } } @Override public Dimension getPreferredSize() { return new Dimension(PREF_W, PREF_H); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.RED); g.fillRect(squareX, squareY, squareW, squareH); } private static void createAndShowGui() { Boxxy2 mainPanel = new Boxxy2(); JFrame frame = new JFrame("Boxxy2"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(mainPanel); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } private class TimerListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { for (Direction dir : dirMap.keySet()) { if (dirMap.get(dir)) { squareX += MOVE_SCALE * dir.getRight(); squareY += MOVE_SCALE * dir.getDown(); } } repaint(); } } public void setMovement(Direction direction, boolean keyPressed) { dirMap.put(direction, keyPressed); } } enum Direction { UP(KeyEvent.VK_UP, 0, -1), DOWN(KeyEvent.VK_DOWN, 0, 1), LEFT(KeyEvent.VK_LEFT, -1, 0), RIGHT(KeyEvent.VK_RIGHT, 1, 0); private int key; private int right; private int down; private Direction(int key, int right, int down) { this.key = key; this.right = right; this.down = down; } public int getKey() { return key; } public int getRight() { return right; } public int getDown() { return down; } } // Actions for the key binding @SuppressWarnings("serial") class MyKeyAction extends AbstractAction { private Boxxy2 boxxy2; private Direction direction; private boolean keyPressed; public MyKeyAction(Boxxy2 boxxy2, Direction direction, boolean keyPressed) { this.boxxy2 = boxxy2; this.direction = direction; this.keyPressed = keyPressed; } @Override public void actionPerformed(ActionEvent e) { boxxy2.setMovement(direction, keyPressed); } }