如何使用java中的键移动矩形

我一直试图找出如何使用箭头键移动矩形,但似乎有问题。
我正在使用KeyListener来检测所有键输入。
我不知道如何使用KeyBinding,因此我不希望解决方案拥有它。
我打算在掌握KeyListener之后立即学习它。 请给我一些如何解决它的建议。

 package expo; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFrame; import javax.swing.JPanel; public class Expo extends JPanel implements KeyListener{ int x = 0; int y = 0; @Override public void keyTyped(KeyEvent e) { //System.out.println("Key Typed"); } @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_DOWN){ System.out.println("Key Pressed" + e.getKeyCode()); y = y + 2; } } @Override public void keyReleased(KeyEvent e) { //System.out.println("Key Released"); } public void paint(Graphics g){ g.setColor(Color.BLUE); g.drawRect(x ,y,100,100); repaint(); } public static void main(String[] args) throws InterruptedException { Expo expo = new Expo(); JFrame f = new JFrame(); f.setVisible(true); f.setSize(500,500); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.addKeyListener(expo); f.add(expo); f.repaint(); } } 

  1. KeyListener使用键绑定API,它解决了KeyListener遭受的与焦点相关的问题。 如何使用键绑定
  2. 不要打破油漆链。 如果覆盖其中一个paint方法,则必须调用它的super实现。
  3. 避免重写paint ,它通常在绘画过程中很高,并且由于绘画的工作方式,在绘制子组件时并不总是被调用,这可能会导致一些有趣的问题。 Convention建议改为使用paintComponent 。 有关详细信息,请参阅AWT和Swing中的 绘画以及执行自定义绘画
  4. 尝试最后调用JFrame#setVisible ,在建立UI之后,您会发现它会导致更少的问题

举个例子…

 import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class Expo extends JPanel { int x = 0; int y = 0; public Expo() { bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { y += 2; if (y + 100 > getHeight()) { y = getHeight() - 100; } repaint(); } }); bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { y -= 2; if (y < 0) { y = 0; } repaint(); } }); } public void bindKeyStrokeTo(int condition, String name, KeyStroke keyStroke, Action action) { InputMap im = getInputMap(condition); ActionMap am = getActionMap(); im.put(keyStroke, name); am.put(name, action); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.BLUE); g.drawRect(x, y, 100, 100); } @Override public Dimension getPreferredSize() { return new Dimension(500, 500); } public static void main(String[] args) throws InterruptedException { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new Expo()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } } 

这一切都很酷,但是现在,当你按住键时,矩形会移动,暂停,然后开始稳定地移动!?

这实际上很正常。 相反,你可以做的是建立一个“更新循环”,它不断监视一组标志的状态,决定在设置这些标志时要做什么并更新UI。

所以,这样做是设置一个Swing Timer ,每40毫秒滴答一次,检查当前“垂直键状态”的状态,相应地更新y位置并安排repaint ,这样可以让我们的运动更加平稳'不依赖于重复击键。

这也certificate了键绑定API的强大function,因为它建立了一个Action来处理向上和向下移动以及相关的键释放......整洁

 import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import javax.swing.AbstractAction; import javax.swing.Action; 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 Expo extends JPanel { int x = 0; int y = 0; public enum VerticalKey { UP, DOWN, NONE; } public enum HorizontalKey { LEFT, RIGHT, NONE; } private VerticalKey verticalKeyState = VerticalKey.NONE; private HorizontalKey horizontalKeyState = HorizontalKey.NONE; public Expo() { bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "pressed.down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new VerticalAction(VerticalKey.DOWN)); bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "released.down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), new VerticalAction(VerticalKey.NONE)); bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "pressed.up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new VerticalAction(VerticalKey.UP)); bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "released.up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), new VerticalAction(VerticalKey.NONE)); Timer timer = new Timer(40, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { switch (verticalKeyState) { case UP: y -= 2; break; case DOWN: y += 2; break; } if (y + 100 > getHeight()) { y = getHeight() - 100; } else if (y < 0) { y = 0; } repaint(); } }); timer.start(); } public void bindKeyStrokeTo(int condition, String name, KeyStroke keyStroke, Action action) { InputMap im = getInputMap(condition); ActionMap am = getActionMap(); im.put(keyStroke, name); am.put(name, action); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.BLUE); g.drawRect(x, y, 100, 100); } public void setVerticalKeyState(VerticalKey verticalKeyState) { this.verticalKeyState = verticalKeyState; System.out.println(verticalKeyState); } public void setHorizontalKeyState(HorizontalKey horizontalKeyState) { this.horizontalKeyState = horizontalKeyState; } public class VerticalAction extends AbstractAction { private VerticalKey verticalKey; public VerticalAction(VerticalKey verticalKeys) { this.verticalKey = verticalKeys; } @Override public void actionPerformed(ActionEvent e) { setVerticalKeyState(verticalKey); } } @Override public Dimension getPreferredSize() { return new Dimension(500, 500); } public static void main(String[] args) throws InterruptedException { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new Expo()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } } 

只需更改这两段代码:

 @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_DOWN){ System.out.println("Key Pressed" + e.getKeyCode()); y = y + 2; repaint();//add this line to update the UI } } 

 public void paint(Graphics g){ super.paint(g);//you should always call the super-method first g.setColor(Color.BLUE); g.drawRect(x ,y,100,100); } 

这将解决问题。 虽然我建议覆盖paintComponent而不是paint (请阅读本文中有关“绘制方法”的部分: 在AWT和Swing中绘制 )。 基本上我所做的更改改变如下:
keyPressed这一行: repaint(); 将在广场移动后更新UI。 实际上,广场在移动之前已被移动,但在UI更新之前,更改将不会显示。 在paint这一行: super.paint(g); 使面板首先执行默认绘画,其中包括清除整个面板。 我已经删除了repaint(); 打电话,因为它完全没用。

注意:如果使用paintComponent而不是paint ,则必须将第一次调用从super.paint(g)更改为super.paintComponent(g)以避免super.paintComponent(g)