Make an JLabel move with Key Bidings

2020-05-10 07:56发布

问题:

I have a short script made in swing, people keep telling me that I need to use Key bindings to get the Jlabel to move but I can't figure out how to do it. anyone have any idea on how to implement Key bindings in a way it works that does not use a Key Listener or that will be a problem if I add a button?

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.border.EmptyBorder;
import java.awt.CardLayout;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import java.awt.Color;
import java.awt.Font;

public class Screen extends JFrame {

    private JPanel contentPane;
    int x,y;

    /**
     * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                Screen frame = new Screen();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the frame.
 */
public Screen() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 450, 300);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(new CardLayout(0, 0));

    JPanel panel = new JPanel();
    contentPane.add(panel, "p1");
    panel.setLayout(null);

    JButton btnPlay = new JButton("Play");
    btnPlay.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            CardLayout c =(CardLayout)(contentPane.getLayout());
            c.show(contentPane, "p2");
        }
    });
    btnPlay.setBounds(185, 164, 53, 23);
    panel.add(btnPlay);

    JLabel lblGame = new JLabel("Game");
    lblGame.setHorizontalAlignment(SwingConstants.CENTER);
    lblGame.setBounds(189, 28, 46, 14);
    panel.add(lblGame);

    JPanel panel_1 = new JPanel();
    contentPane.add(panel_1, "p2");
    panel_1.setLayout(null);

    JLabel player = new JLabel("P");
    player.setHorizontalAlignment(SwingConstants.CENTER);
    player.setFont(new Font("Tahoma", Font.BOLD, 27));
    player.setForeground(Color.BLACK);
    player.setBackground(Color.BLACK);
    player.setBounds(x, y, 51, 40);
        panel_1.add(player);
}
}

回答1:

As with most things, start having a look at the tutorials, How to Use Key Bindings, as pretty much any answer is simply going to be based on these

You could do something as simple as this...

import com.sun.glass.events.KeyEvent;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
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 interface Movable {
        public void changeLocation(int xDelta, int yDelta);
    }

    public class TestPane extends JPanel implements Movable {

        private JLabel player;

        public TestPane() {
            setLayout(null);
            player = new JLabel("X");
            player.setSize(player.getPreferredSize());
            add(player);

            setupKeyBindings();
        }

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

        protected void setupKeyBindings() {
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "up");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "down");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");

            int xDelta = player.getWidth();
            int yDelta = player.getHeight();

            am.put("up", new MoveAction(this, 0, -yDelta));
            am.put("down", new MoveAction(this, 0, yDelta));
            am.put("left", new MoveAction(this, -xDelta, 0));
            am.put("right", new MoveAction(this, xDelta, 0));
        }

        @Override
        public void changeLocation(int xDelta, int yDelta) {
            int xPos = player.getX() + xDelta;
            int yPos = player.getY() + yDelta;
            if (xPos + player.getWidth() > getWidth()) {
                xPos = getWidth() - player.getWidth();
            } else if (xPos < 0) {
                xPos = 0;
            }
            if (yPos + player.getHeight() > getHeight()) {
                yPos = getHeight() - player.getHeight();
            } else if (xPos < 0) {
                yPos = 0;
            }
            player.setLocation(xPos, yPos);
        }

    }

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

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

        @Override
        public void actionPerformed(ActionEvent e) {
            movable.changeLocation(xDelta, yDelta);
        }

    }

}

Disclaimer...

As I have, repeatedly, told either you or your fellow class mates, you shouldn't be using components this way. Instead, you should be following a custom painting route, which will provide you with greater flexibility and far less issues in the long run.

import com.sun.glass.events.KeyEvent;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
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.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 interface Movable {

        public void changeLocation(int xDelta, int yDelta);
    }

    public class TestPane extends JPanel implements Movable {

        private Rectangle player;

        public TestPane() {
            String text = "X";
            FontMetrics fm = getFontMetrics(getFont());
            int width = fm.stringWidth(text);
            int height = fm.getHeight();

            player = new Rectangle(0, 0, width, height);

            setupKeyBindings();
        }

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

        protected void setupKeyBindings() {
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "up");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "down");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");

            int xDelta = player.width;
            int yDelta = player.height;

            am.put("up", new MoveAction(this, 0, -yDelta));
            am.put("down", new MoveAction(this, 0, yDelta));
            am.put("left", new MoveAction(this, -xDelta, 0));
            am.put("right", new MoveAction(this, xDelta, 0));
        }

        @Override
        public void changeLocation(int xDelta, int yDelta) {
            int xPos = player.x + xDelta;
            int yPos = player.y + yDelta;
            if (xPos + player.width > getWidth()) {
                xPos = getWidth() - player.width;
            } else if (xPos < 0) {
                xPos = 0;
            }
            if (yPos + player.height > getHeight()) {
                yPos = getHeight() - player.height;
            } else if (xPos < 0) {
                yPos = 0;
            }
            player.setLocation(xPos, yPos);
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            g2d.draw(player);
            FontMetrics fm = g2d.getFontMetrics();
            g2d.drawString("X", player.x, player.y + fm.getAscent());
            g2d.dispose();
        }

    }

    public class MoveAction extends AbstractAction {

        private Movable movable;
        private int xDelta;
        private int yDelta;

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

        @Override
        public void actionPerformed(ActionEvent e) {
            movable.changeLocation(xDelta, yDelta);
        }

    }

}

You should also be making appropriate use layout managers. These will safe you a lot of hair and time.

See Laying Out Components Within a Container for more details