当你释放一个移动它的键时,如何让一个矩形停止? [英] How to get a rectangle to stop when you release a key that moves it?

查看:98
本文介绍了当你释放一个移动它的键时,如何让一个矩形停止?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个JFrame,其中心有一个矩形,当我按某些键时它会移动。这一切都很好看,但是当我释放按键时矩形会继续运行。事实上,如果我多次按一个键,矩形会加速。这可能(肯定)是因为当我按住一个键时,我正在使用一个计时器来解决那个令人讨厌的0.5秒输入延迟。

I've created a JFrame with a rectangle in the center of it that moves when I press certain keys. It's all nice and dandy, but the rectangle keeps going when I release the keys. In fact, if I press a key multiple times, the rectangle accelerates. This is probably (definitely) because I'm using a timer to get around that pesky 0.5-second input delay when holding a key down.

我想我必须把在 keyReleased()方法中的某些东西,但我不知道放在那里的东西。有小费吗?谢谢。

I think I have to put something in the keyReleased() method, but I'm at a loss for what to put there. Any tips? Thanks.

PS:不要因为我没有使用键绑定而对我大喊大叫。我知道:他们是更好的东西。但我现在关注的是关键听众。

PS: Please don't yell at me for not using key bindings. I know: they're better and stuff. But I'm focusing on key listeners at the moment.

节目:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;

@SuppressWarnings ("serial")
public class GameFrame extends JComponent implements KeyListener
{
    static GameFrame gameFrame = new GameFrame();

    public int x = 350;
    public int y = 250;
    public int keyCode;

    public static void main (String[] args)
    {
        JFrame frame = new JFrame ("Java Game");
        frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
        frame.setSize (800, 600);
        frame.setResizable (false);
        frame.getContentPane().setBackground (Color.WHITE);
        frame.getContentPane().add (gameFrame);
        frame.addKeyListener (gameFrame);
        frame.setVisible (true);
    }

    @Override
    public void paintComponent (Graphics graphics)
    {
        super.paintComponent (graphics);
        graphics.setColor (Color.BLACK);
        graphics.fillRect (x, y, 100, 100);
    }

    public void keyPressed (KeyEvent event)
    {
        keyCode = event.getKeyCode();

        new Timer (100, new ActionListener()
        {
            public void actionPerformed (ActionEvent event)
            {
                if (keyCode == KeyEvent.VK_LEFT)
                {
                    x--;
                    repaint();
                }
                if (keyCode == KeyEvent.VK_RIGHT)
                {
                    x++;
                    repaint();
                }
                if (keyCode == KeyEvent.VK_UP)
                {
                    y--;
                    repaint();
                }
                if (keyCode == KeyEvent.VK_DOWN)
                {
                    y++;
                    repaint();
                }
            }
        }).start();
    }

    public void keyReleased (KeyEvent event) {}
    public void keyTyped (KeyEvent event) {}
}


推荐答案


  • 避免 KeyListener ,严重的是,它们比它们的价值更麻烦,而是使用密钥绑定API。 如何使用密钥绑定

    • Avoid KeyListener, seriously, they are more trouble than they are worth, use the key bindings API instead. How to Use Key Bindings
    • 您可以通过多种方式实现这一目标。更好的方法之一是使用间接方法。也就是说,用户按下一个键并举起一个标志来指示按下哪个键,他们释放键,重置标志,表示不再按下该键。

      There are a number of ways you might achieve this. One of the better way is to use a indirect approach. That is, the user presses a key and you raise a flag to indicate which is pressed, they release the key, you reset the flag, indicating that the key is no longer pressed.

      然后使用某种更新循环来根据哪些键当前处于活动状态来更改对象的位置。

      You then use some kind of update loop to change the position of the object based which keys are currently active.

      但为什么这么麻烦我听到你问。当用户按下某个键时,它们是第一次按键和重复按键通知之间的短暂延迟(当按键关闭时,操作系统会向您发送按键事件直到它被释放),这使得该动作看起来有点交错 。

      But why go to so much hassle I hear you ask. When a user presses a key, they is a short delay between the first key press and repeated key notification (while the key is down, the OS will send you key events until it is released), this makes the movement look a little "staggered".

      相反,我们引发标志并使用一个常量更新循环来根据标志的状态更改对象的状态,从而平滑键事件,例如......

      Instead, we raise flag and use a constant update loop to make changes to the state of the object based on the state of the flags, which smooths out the key events, for example...

      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 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 Test{
      
          public static void main(String[] args) {
              new Test();
          }
      
          public Test() {
              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 TestPane());
                      frame.pack();
                      frame.setLocationRelativeTo(null);
                      frame.setVisible(true);
                  }
              });
          }
      
          public static class TestPane extends JPanel {
      
              public enum HorizontalMovement {
                  NONE,
                  LEFT,
                  RIGHT
              }
      
              private HorizontalMovement horizontalMovement = HorizontalMovement.NONE;
      
              private int xPos = 0;
      
              public TestPane() {
                  addKeyPressedBinding("left.pressed", KeyEvent.VK_LEFT, new MoveHorizontialAction(HorizontalMovement.LEFT));
                  addKeyPressedBinding("right.pressed", KeyEvent.VK_RIGHT, new MoveHorizontialAction(HorizontalMovement.RIGHT));
                  addKeyReleasedBinding("left.relesed", KeyEvent.VK_LEFT, new MoveHorizontialAction(HorizontalMovement.NONE));
                  addKeyReleasedBinding("right.relesed", KeyEvent.VK_RIGHT, new MoveHorizontialAction(HorizontalMovement.NONE));
      
                  Timer timer = new Timer(40, new ActionListener() {
                      @Override
                      public void actionPerformed(ActionEvent e) {
                          switch (horizontalMovement) {
                              case LEFT:
                                  xPos--;
                                  break;
                              case RIGHT:
                                  xPos++;
                                  break;
                          }
                          if (xPos < 0) {
                              xPos = 0;
                          } else if (xPos + 50 > getWidth()) {
                              xPos = getWidth() - 50;
                          }
                          repaint();
                      }
                  });
                  timer.start();
      
              }
      
              protected void addKeyPressedBinding(String name, int keyCode, Action action) {
                  KeyStroke ks = KeyStroke.getKeyStroke(keyCode, 0, false);
                  addKeyBinding(name, ks, action);
              }
      
              protected void addKeyReleasedBinding(String name, int keyCode, Action action) {
                  KeyStroke ks = KeyStroke.getKeyStroke(keyCode, 0, true);
                  addKeyBinding(name, ks, action);
              }
      
              protected void addKeyBinding(String name, KeyStroke ks, Action action) {
                  InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
                  ActionMap am = getActionMap();
      
                  im.put(ks, name);
                  am.put(name, action);
              }
      
              @Override
              public Dimension getPreferredSize() {
                  return new Dimension(200, 200);
              }
      
              @Override
              protected void paintComponent(Graphics g) {
                  super.paintComponent(g);
                  Graphics2D g2d = (Graphics2D) g.create();
                  Rectangle box = new Rectangle(xPos, (getHeight() - 50) / 2, 50, 50);
                  g2d.setColor(Color.BLUE);
                  g2d.fill(box);
                  g2d.dispose();
              }
      
              protected void addKeyBinding(String left, int VK_LEFT, MoveHorizontialAction moveHorizontialAction) {
                  throw new UnsupportedOperationException("Not supported yet.");
              }
      
              protected class MoveHorizontialAction extends AbstractAction {
      
                  private HorizontalMovement movement;
      
                  public MoveHorizontialAction(HorizontalMovement movement) {
                      this.movement = movement;
                  }
      
                  @Override
                  public void actionPerformed(ActionEvent e) {
                      horizontalMovement = movement;
                  }
      
              }
      
          }
      
      }
      

      这篇关于当你释放一个移动它的键时,如何让一个矩形停止?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆