How to move move a rectangle in JFrame using KeyListener?

跟風遠走 提交于 2019-12-11 02:18:01

问题


I'm trying to get a rectangle in my JFrame to move when I press a given key on the keyboard, but I'm seemingly having a hard time doing that. Here's my code:

package TestPackage;

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

public class Mainframe extends JComponent implements KeyListener
{
    private static final long serialVersionUID = 1L;

    int x = 350;
    int y = 250;

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

    public void paint (Graphics graphics)
    {
        graphics.setColor (Color.BLACK);
        graphics.fillRect (x, y, 100, 100);
    }

    public void keyPressed (KeyEvent event)
    {
        if (event.getKeyCode() == KeyEvent.VK_A)
        {
            x++;
            repaint();
        }
        else if (event.getKeyCode() == KeyEvent.VK_D)
        {
            y++;
            repaint();
        }
    }

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

I'm sure it's a problem with my KeyListener, as everything else works perfectly. Does anybody know what I'm doing wrong? Thanks.


回答1:


  1. You're creating two instances of MainFrame, one you add to the frame and one you use as the JFrame's KeyListener, this means that any modifications the KeyListener instance makes to the x/y values, won't be seen by the instance on the UI
  2. Don't use KeyListener, it has too many focus related issues, use the Key Bindings API which was designed to overcome these issues. See How to Use Key Bindings
  3. Don't override paint (and especially if you're not going to call super.paint), instead, you should override the paintComponent method (and call super.paintComponent). See Painting in AWT and Swing and Performing Custom Painting for more details
  4. Make sure you are creating and modifying the UI only from within the context of the Event Dispatching Thread, see Initial Threads for more details

For example...

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Mainframe extends JComponent {

    private static final long serialVersionUID = 1L;

    int x = 350;
    int y = 250;

    public static void main(String[] args) {
        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("Mainframe");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setSize(800, 600);
                frame.setFocusable(true);
                frame.getContentPane().setBackground(Color.WHITE);
                frame.getContentPane().add(new Mainframe());
                frame.setVisible(true);
            }
        });
    }

    public Mainframe() {
        bindKeyWith("y.up", KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), new VerticalAction(-1));
        bindKeyWith("y.down", KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), new VerticalAction(1));
        bindKeyWith("x.left", KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), new HorizontalAction(-1));
        bindKeyWith("x.right", KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), new HorizontalAction(1));
    }

    protected void bindKeyWith(String name, KeyStroke keyStroke, Action action) {
        InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
        ActionMap am = getActionMap();

        im.put(keyStroke, name);
        am.put(name, action);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
        g.setColor(Color.BLACK);
        g.fillRect(x, y, 100, 100);
    }

    public abstract class MoveAction extends AbstractAction {

        private int delta;

        public MoveAction(int delta) {
            this.delta = delta;
        }

        public int getDelta() {
            return delta;
        }

        protected abstract void applyDelta();

        @Override
        public void actionPerformed(ActionEvent e) {
            applyDelta();
        }

    }

    public class VerticalAction extends MoveAction {

        public VerticalAction(int delta) {
            super(delta);
        }

        @Override
        protected void applyDelta() {
            int delta = getDelta();
            y += delta;
            if (y < 0) {
                y = 0;
            } else if (y + 100 > getHeight()) {
                y = getHeight() - 100;
            }
            repaint();
        }

    }
    public class HorizontalAction extends MoveAction {

        public HorizontalAction(int delta) {
            super(delta);
        }

        @Override
        protected void applyDelta() {
            int delta = getDelta();
            x += delta;
            if (x < 0) {
                x = 0;
            } else if (x + 100 > getWidth()) {
                x = getWidth() - 100;
            }
            repaint();
        }

    }
}



回答2:


make your main like this and it will work

 public static void main (String[] args)
    {
        JFrame frame = new JFrame ("Mainframe");
        JComponent test = new Mainframe();
        frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
        frame.setSize (800, 600);
        frame.setFocusable (true);
        frame.getContentPane().setBackground (Color.WHITE);
        frame.getContentPane().add (test);
        frame.addKeyListener ((KeyListener) test);
        frame.setVisible (true);
    }


来源:https://stackoverflow.com/questions/28228121/how-to-move-move-a-rectangle-in-jframe-using-keylistener

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!