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

时间:2015-05-27 22:59:58

标签: java keylistener

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

KeyListener

2 个答案:

答案 0 :(得分:1)

  1. 使用KeyListener上的键绑定API,它解决了KeyListener遭受的焦点相关问题。 How to Use Key Bindings
  2. 不要打破油漆链。如果您覆盖其中一种paint方法,则必须将其称为super实施方式。
  3. 避免覆盖paint,它通常在绘画过程中处于高位,并且由于绘画的工作方式,在绘制子组件时不会总是被调用,这可能会导致一些有趣的问题。公约建议改为使用paintComponent。有关详细信息,请参阅Painting in AWT and SwingPerforming Custom Painting
  4. 最后尝试拨打JFrame#setVisible,在您建立用户界面后,您会发现它会导致较少的问题
  5. 作为一个例子......

    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);
                }
            });
        }
    
    }
    

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

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

    所以,这样做,是设置一个Swing Timer,每40毫秒滴答一次,检查当前&#34;垂直键状态&#34;的状态,更新y位置相应地安排一个repaint,这样可以让我们更顺畅地运动,因为我们不依赖于重复击键。

    这也证明了键绑定API的强大功能,因为它建立了一个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);
                }
            });
        }
    
    }
    

答案 1 :(得分:0)

只需更改这两段代码:

@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(请参阅有关&#34; The Paint Methods&#34;在本文中的部分:Painting in AWT and Swing)。基本上我改变了以下内容:
keyPressed这一行:repaint();将在广场移动后更新用户界面。实际上广场在移动之前已被移动,但是在更新UI之前,更改不会显示。在paint这一行:super.paint(g);使面板首先执行默认绘制,其中包括清除整个面板。我已经删除了repaint();电话,因为它完全没用。

注意: 如果您使用paintComponent代替paint,则必须将第一个来电从super.paint(g)更改为super.paintComponent(g)以避免堆叠溢出。