Moving a Rectangle Using KeyListener

2019-04-17 09:55发布

问题:

I'm trying to get a rectangle to move using KeyListener. I have seen others use the same code but for some reason I can't get it to move. Right now the rectangle does show up. I'm not sure if I'm forgetting something if there is something I'm missing. Here's my code:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.Graphics;
public class roomwars extends JPanel implements ActionListener, KeyListener {
    //public JPanel pane;
    public JFrame frame;
    public JButton start, help;
    public JTextField box;
    int x=0, y=0, velx =0, vely =0;
    Timer t = new Timer(5, this);
    public void run(){
        frame = new JFrame("ROOM WARS!");
        frame.setSize(700, 700);
        frame.setVisible(true);
        frame.add(this);
    }
    public void second (){
        t.start();
        addKeyListener(this);
        //setFocusalbe(true);
        //SETFocusTraversalKeyEnabled(false);
    }
    public void paintComponent(Graphics g) {
        Color mypurple = new Color(34, 0, 56);
        g.setColor(mypurple);
        g.fillRect(x, y, 30, 30);
        //g.setColor(Color.PINK);
        //g.fillRect(655,632,30,30);
    }

    public void actionPerformed(ActionEvent e){
        repaint();
        x+= velx;
        y+= vely;
    }

     public void keyPressed(KeyEvent e){
        int code = e.getKeyCode();
        if (code == KeyEvent.VK_UP){
            vely = -1;
            velx = 0;
        }
        else if (code == KeyEvent.VK_DOWN) {
            vely = 1;
            velx = 0;
        }
        else if (code == KeyEvent.VK_RIGHT) {
            velx = -1;
            vely = 0;
        }
        else if (code == KeyEvent.VK_LEFT) {
            velx = 1;
            vely = 0;
        }
    }
    public void keyTyped(KeyEvent e){}
    public void keyReleased(KeyEvent e) {}

    public static void main(String[] args) {
        new roomwars().run();
    }

}

回答1:

Apart from not honouring the paint chain (and calling super.paintComponent), you're primary issue is the use of KeyListener.

A short amount of searching will tell you quickly that KeyListener is notorious for not responding as is generally unreliable.

The most common solution is to use the key bindings API

The following is very simply example of implementing key bindings into your current code base

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 java.io.IOException;
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 Test {

    public static void main(String[] args) throws IOException, InterruptedException {
        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 RoomWars());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class RoomWars extends JPanel implements ActionListener {
        //public JPanel pane;

        int x = 0, y = 0, velx = 0, vely = 0;
        Timer t = new Timer(5, this);

        public RoomWars() {
            t.start();

            InputMap im = getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            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_DOWN, 0, false), "down.pressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "down.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("up.pressed", new MoveAction(-1, 0));
            am.put("up.released", new MoveAction(0, 0));
            am.put("down.pressed", new MoveAction(1, 0));
            am.put("down.released", new MoveAction(0, 0));
            am.put("left.pressed", new MoveAction(0, -1));
            am.put("left.released", new MoveAction(0, 0));
            am.put("right.pressed", new MoveAction(0, 1));
            am.put("right.released", new MoveAction(0, 0));
        }

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

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Color mypurple = new Color(34, 0, 56);
            g.setColor(mypurple);
            g.fillRect(x, y, 30, 30);
            //g.setColor(Color.PINK);
            //g.fillRect(655,632,30,30);
        }

        public class MoveAction extends AbstractAction {
            private int yDelta;
            private int xDelta;

            public MoveAction(int yDelta, int xDelta) {
                this.yDelta = yDelta;
                this.xDelta = xDelta;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                vely = yDelta;
                velx = xDelta;
            }
        }

        public void actionPerformed(ActionEvent e) {
            repaint();
            x += velx;
            y += vely;
        }

    }
}


回答2:

Note that in your code snippet, second() isn't called so the key listener isn't registered. Your panel also needs to be focusable in order to receive key press events. You may also want to call super.paintComponent() first in your method.

See here for details:

https://docs.oracle.com/javase/tutorial/uiswing/events/keylistener.html