Can't move JLabel on JPanel

2020-02-16 03:37发布

问题:

Ok, so I am making a monopoly game. I so far have a JFrame, with a JPanel acting as a board. I have loaded all necessary images. I create a Player object which extends JLabel, to represent the player on the board.

I am trying to set the location of (in hopes of moving pieces around the board) Player object (which is a JLabel), on the board (which is a JPanel). I tried the .setLocation method, .setBounds method.

For some reason, no matter what i do the Player object only shows up on the top middle of the JPanel. I was wondering how I could move the Player object on my board.

JFrame code (I attempt to move the JLabel in the bottom of the constructor):

   package com.Game.Monopoly;

    import javax.imageio.ImageIO;
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JList;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.Timer;

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Image;
    import java.awt.LayoutManager;
    import java.awt.Point;
    import java.awt.SystemColor;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import java.io.IOException;

    import net.miginfocom.swing.MigLayout;

    //a class that represent the board (JFrame) and all of it components 
    public class GameFrame extends JFrame {
        private final double SCALE;
        // all the graphical components
        private Board board;
        private JLabel lblPlayerMoney;
        private JLabel lblCurrentPlayer;
        private JLabel lblDice1;
        private JLabel lblDice2;
        private JList lstPropertiesList;
        private JButton btnEndTurn;
        private JButton btnBuyProperty;
        private JButton btnRollDice;

        // all images needed
        private ImageIcon imgDice1;
        private ImageIcon imgDice2;
        private ImageIcon imgDice3;
        private ImageIcon imgDice4;
        private ImageIcon imgDice5;
        private ImageIcon imgDice6;
        private ImageIcon icnAirplane;

        // all players
        private Player[] playerList;
        // all properties
        private Property[] propertiesList;

        public GameFrame(double scale) {
            // SCALE = scale;
            SCALE = 1;

            // set up the JFrame
            setResizable(true);
            setTitle("Monopoly");
            // etUndecorated(true);
            // set size to a scale of 1080p
            setSize((int) (1920 * SCALE), (int) (1080 * SCALE));
            setLayout(new MigLayout());
            loadImages();

            // add the components to the frame
            board = new Board(SCALE);
            board.setPreferredSize(new Dimension((int) (1024 * SCALE),
                    (int) (1024 * SCALE)));
            board.setBackground(Color.BLACK);
            add(board, "east, gapbefore 80");
            lblCurrentPlayer = new JLabel("Current Player:" + " Player 1");
            add(lblCurrentPlayer, "wrap");
            lblPlayerMoney = new JLabel("Player1's money:" + "$14000000");
            add(lblPlayerMoney, "wrap");
            lstPropertiesList = new JList();
            add(new JScrollPane(lstPropertiesList),
                    "span 2 2, grow, height 70:120:200");
            btnRollDice = new JButton("Roll Dice");
            add(btnRollDice, "wrap");
            lblDice1 = new JLabel(imgDice1);
            add(lblDice1);
            lblDice2 = new JLabel(imgDice1);
            add(lblDice2, "wrap");
            btnBuyProperty = new JButton("Buy Property");
            add(btnBuyProperty, "wrap, top");
            btnEndTurn = new JButton("End Turn");
            add(btnEndTurn, "aligny bottom");

            setUpEventListeners();
            loadProperties();

            // load players
            playerList = new Player[6];
            playerList[0] = new Player("Player 1", icnAirplane);

            // add Players to the board

            board.add(playerList[0]);
            playerList[0].setLocation(new Point(500, 230));
        }

        public static void main(String[] args) {
            GameFrame board = new GameFrame(1);
            board.setVisible(true);

        }

        // method to add event listeners
        public void setUpEventListeners() {

            // roll dice
            btnRollDice.addActionListener(new ActionListener() {
                // creates an object with an timers to help with rolling dice
                class RollDice implements ActionListener {
                    private Timer time = new Timer(152, this);
                    private int count = 0;

                    public void actionPerformed(ActionEvent e) {
                        count++;
                        if (count == 21)
                            time.stop();

                        int whatDice1 = (int) (Math.random() * 6) + 1;
                        int whatDice2 = (int) (Math.random() * 6) + 1;

                        // set the icons of the labels according to the random
                        // number

                        if (whatDice1 == 1)
                            lblDice1.setIcon(imgDice1);
                        else if (whatDice1 == 2)
                            lblDice1.setIcon(imgDice2);
                        else if (whatDice1 == 3)
                            lblDice1.setIcon(imgDice3);
                        else if (whatDice1 == 4)
                            lblDice1.setIcon(imgDice4);
                        else if (whatDice1 == 5)
                            lblDice1.setIcon(imgDice5);
                        else if (whatDice1 == 6)
                            lblDice1.setIcon(imgDice6);

                        if (whatDice2 == 1)
                            lblDice2.setIcon(imgDice1);
                        else if (whatDice2 == 2)
                            lblDice2.setIcon(imgDice2);
                        else if (whatDice2 == 3)
                            lblDice2.setIcon(imgDice3);
                        else if (whatDice2 == 4)
                            lblDice2.setIcon(imgDice4);
                        else if (whatDice2 == 5)
                            lblDice2.setIcon(imgDice5);
                        else if (whatDice2 == 6)
                            lblDice2.setIcon(imgDice6);
                    }

                    public void roll() {
                        count = 0;
                        time.start();
                    }
                }

                // create a new dice roll object
                RollDice roll = new RollDice();

                // if the roll dice button is clicked
                public void actionPerformed(ActionEvent arg0) {
                    roll.roll();
                }

            });

        }

        // load all images to memory
        public void loadImages() {
            BufferedImage i = null;
            try {
                i = ImageIO.read((getClass().getResource("/resources/Dice 1.png")));
                imgDice1 = new ImageIcon(i.getScaledInstance(100, 100,
                        java.awt.Image.SCALE_SMOOTH));

                i = ImageIO.read((getClass().getResource("/resources/Dice 2.png")));
                imgDice2 = new ImageIcon(i.getScaledInstance(100, 100,
                        java.awt.Image.SCALE_SMOOTH));

                i = ImageIO.read((getClass().getResource("/resources/Dice 3.png")));
                imgDice3 = new ImageIcon(i.getScaledInstance(100, 100,
                        java.awt.Image.SCALE_SMOOTH));

                i = ImageIO.read((getClass().getResource("/resources/Dice 4.png")));
                imgDice4 = new ImageIcon(i.getScaledInstance(100, 100,
                        java.awt.Image.SCALE_SMOOTH));

                i = ImageIO.read((getClass().getResource("/resources/Dice 5.png")));
                imgDice5 = new ImageIcon(i.getScaledInstance(100, 100,
                        java.awt.Image.SCALE_SMOOTH));

                i = ImageIO.read((getClass().getResource("/resources/Dice 6.png")));
                imgDice6 = new ImageIcon(i.getScaledInstance(100, 100,
                        java.awt.Image.SCALE_SMOOTH));

                i = ImageIO.read((getClass()
                        .getResource("/resources/Airplane Icon.png")));
                icnAirplane = new ImageIcon(i.getScaledInstance(40, 40,
                        java.awt.Image.SCALE_SMOOTH));

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

        // load all properties
        public void loadProperties() {
            propertiesList = new Property[40];

            // set up the properties list
            // (name, index, isBuyable, price, initial rent)
            propertiesList[0] = new Property("Go", 0, false, 0, 0);
            propertiesList[1] = new Property("Jacob's Field", 1, true, 600000,
                    20000);
            propertiesList[2] = new Property("Community Chest", 2, false, 0, 0);
            propertiesList[3] = new Property("Texas Stadium", 3, true, 600000,
                    40000);
            propertiesList[4] = new Property("Income Tax", 4, false, 0, 0);
            propertiesList[5] = new Property("O'Hare International Airport", 5,
                    true, 2000000, 250000);
            propertiesList[6] = new Property("Grand Ole Opry", 6, true, 1000000,
                    60000);
            propertiesList[7] = new Property("Chance", 7, false, 0, 0);

        }
    }

JPanel Code:

package com.Game.Monopoly;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class Board extends JPanel {
    private static final long serialVersionUID = 1L;
    private Image board;

    public Board(double scale) {
        this.setPreferredSize(new Dimension((int) (1024 * scale),
                (int) (1024 * scale)));

        BufferedImage i = null;
        try {
            i = ImageIO.read((getClass().getResource("/resources/monopoly-board-web.jpg")));

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        board = i.getScaledInstance((int) (1024 * scale), (int) (1024 * scale), java.awt.Image.SCALE_SMOOTH);

    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(board, 0, 0, this);
    }

}

Player Object Code:

package com.Game.Monopoly;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

//a class representing a player with its graphical component 
public class Player extends JLabel {

    private String playerName;
    private int money;
    private Property[] propertiesOwned;

    public Player(String n, ImageIcon icon) {
        playerName = n;
        this.setIcon(icon);
    }

    // changes the amount of money available 
    public void changeMoney(int amount) {
        money = money + amount;
    }

    public void movePlayer(int x, int y){ 
        this.setLocation(x, y);
    }

}

回答1:

There are a couple of ways you can achieve this, personally, the simplest would be to use custom painting directly and not bother with using Swing based components for the players.

The basic problem you have is JPanel uses a FlowLayout by default, which means that you will always be fighting layout manager. In this case you might consider using a custom layout manager, for example...

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Monopoly {

    public static void main(String[] args) {
        new Monopoly();
    }

    public Monopoly() {
        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 MonopolyBoard());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MonopolyBoard extends JPanel {

        private List<JLabel> players;

        public MonopolyBoard() {
            setLayout(new MonopolyBoardLayout());

            players = new ArrayList<>(2);
            try {
                players.add(makePlayer("/Dog.png"));
                players.add(makePlayer("/Car.png"));

                for (JLabel player : players) {
                    add(player, new Integer(0));
                }
            } catch (IOException exp) {
                exp.printStackTrace();
            }

            Timer timer = new Timer(1000, new ActionListener() {
                private int count = 0;
                private Random rnd = new Random();

                @Override
                public void actionPerformed(ActionEvent e) {
                    int playerIndex = count % players.size();
                    JLabel player = players.get(playerIndex);

                    MonopolyBoardLayout layout = (MonopolyBoardLayout) getLayout();
                    int position = layout.getPosition(player);

                    position += rnd.nextInt(5) + 1;
                    if (position > 35) {
                        position -= 35;
                    }

                    layout.setPosition(player, position);

                    revalidate();
                    repaint();
                    count++;
                }
            });
            timer.start();
        }

        protected JLabel makePlayer(String path) throws IOException {
            JLabel label = new JLabel(new ImageIcon(ImageIO.read(getClass().getResource(path))), JLabel.CENTER);
            return label;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int width = getWidth();
            int height = getHeight();

            for (int index = 0; index < 36; index++) {
                Rectangle bounds = MonopolyBoardLayoutHelper.getCellBounds(index, width, height);
                g2d.draw(bounds);
            }

            g2d.dispose();
        }

    }

    public static class MonopolyBoardLayoutHelper {

        private static Map<Integer, Point> mapBoardCells;

        static {
            mapBoardCells = new HashMap<>(25);

            mapBoardCells.put(10, new Point(0, 8));
            mapBoardCells.put(11, new Point(0, 7));
            mapBoardCells.put(12, new Point(0, 6));
            mapBoardCells.put(13, new Point(0, 5));
            mapBoardCells.put(14, new Point(0, 4));
            mapBoardCells.put(15, new Point(0, 3));
            mapBoardCells.put(16, new Point(0, 2));
            mapBoardCells.put(17, new Point(0, 1));
            mapBoardCells.put(18, new Point(0, 0));

            mapBoardCells.put(0, new Point(9, 9));
            mapBoardCells.put(1, new Point(8, 9));
            mapBoardCells.put(2, new Point(7, 9));
            mapBoardCells.put(3, new Point(6, 9));
            mapBoardCells.put(4, new Point(5, 9));
            mapBoardCells.put(5, new Point(4, 9));
            mapBoardCells.put(6, new Point(3, 9));
            mapBoardCells.put(7, new Point(2, 9));
            mapBoardCells.put(8, new Point(1, 9));
            mapBoardCells.put(9, new Point(0, 9));

            mapBoardCells.put(19, new Point(1, 0));
            mapBoardCells.put(20, new Point(2, 0));
            mapBoardCells.put(21, new Point(3, 0));
            mapBoardCells.put(22, new Point(4, 0));
            mapBoardCells.put(23, new Point(5, 0));
            mapBoardCells.put(24, new Point(6, 0));
            mapBoardCells.put(25, new Point(7, 0));
            mapBoardCells.put(26, new Point(8, 0));
            mapBoardCells.put(27, new Point(9, 0));

            mapBoardCells.put(28, new Point(9, 1));
            mapBoardCells.put(29, new Point(9, 2));
            mapBoardCells.put(30, new Point(9, 3));
            mapBoardCells.put(31, new Point(9, 4));
            mapBoardCells.put(32, new Point(9, 5));
            mapBoardCells.put(33, new Point(9, 6));
            mapBoardCells.put(34, new Point(9, 7));
            mapBoardCells.put(35, new Point(9, 8));

        }

        public static Rectangle getCellBounds(int index, int width, int height) {
            Rectangle bounds = new Rectangle(0, 0, 0, 0);
            int size = Math.min(width, height);
            int cellSize = size / 10;

            int xOffset = (width - size) / 2;
            int yOffset = (height - size) / 2;

            Point point = mapBoardCells.get(index);
            if (point != null) {

                int x = xOffset + (point.x * cellSize);
                int y = yOffset + (point.y * cellSize);
                bounds = new Rectangle(x, y, cellSize, cellSize);

            }

            return bounds;

        }

    }

    public static class MonopolyBoardLayout implements LayoutManager2 {

        public static final int DEFAULT_CELL_SIZE = 64;

        private Map<Component, Integer> cellConstraints;

        public MonopolyBoardLayout() {
            cellConstraints = new HashMap<>(5);
        }

        public Integer getPosition(Component comp) {
            return cellConstraints.get(comp);
        }

        public void setPosition(Component comp, int position) {
            cellConstraints.put(comp, position);
        }

        @Override
        public void addLayoutComponent(Component comp, Object constraints) {
            if (constraints instanceof Integer) {
                int cell = (int) constraints;
                if (cell >= 0 && cell <= 35) {
                    cellConstraints.put(comp, cell);
                } else {
                    throw new IllegalArgumentException(constraints + " is not within the bounds of a valid cell reference (0-35)");
                }
            } else {
                throw new IllegalArgumentException(constraints + " is not a valid cell reference (integer within 0-35)");
            }
        }

        @Override
        public Dimension maximumLayoutSize(Container target) {
            return new Dimension(DEFAULT_CELL_SIZE * 10, DEFAULT_CELL_SIZE * 10);
        }

        @Override
        public float getLayoutAlignmentX(Container target) {
            return 0.5f;
        }

        @Override
        public float getLayoutAlignmentY(Container target) {
            return 0.5f;
        }

        @Override
        public void invalidateLayout(Container target) {
        }

        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        @Override
        public void removeLayoutComponent(Component comp) {
            cellConstraints.remove(comp);
        }

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            return new Dimension(DEFAULT_CELL_SIZE * 10, DEFAULT_CELL_SIZE * 10);
        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            return new Dimension(DEFAULT_CELL_SIZE * 10, DEFAULT_CELL_SIZE * 10);
        }

        @Override
        public void layoutContainer(Container parent) {
            int width = parent.getWidth();
            int height = parent.getHeight();

            Map<Integer, List<Component>> components = new HashMap<>(25);

            for (Component child : parent.getComponents()) {
                Integer cell = cellConstraints.get(child);
                if (cell != null) {
                    List<Component> children = components.get(cell);
                    if (children == null) {
                        children = new ArrayList<>(4);
                        components.put(cell, children);
                    }
                    children.add(child);
                } else {
                    child.setBounds(0, 0, 0, 0);
                }
            }

            for (Map.Entry<Integer, List<Component>> entry : components.entrySet()) {
                int index = entry.getKey();
                Rectangle bounds = MonopolyBoardLayoutHelper.getCellBounds(index, width, height);
                List<Component> comp = entry.getValue();
                int xDelta = 0;
                int yDelta = 0;
                int availableWidth = bounds.width;
                int availableHeight = bounds.height;
                switch (comp.size()) {
                    case 2:
                        availableWidth /= 2;
                        xDelta = availableWidth;
                        break;
                    case 3:
                    case 4:
                        availableWidth /= 2;
                        xDelta = availableWidth;
                        availableHeight /= 2;
                        yDelta = availableHeight;
                        break;
                }
                int x = bounds.x;
                int y = bounds.y;
                for (int count = 0; count < comp.size() && count < 4; count++) {
                    Component child = comp.get(count);
                    child.setSize(availableWidth, availableHeight);
                    child.setLocation(x, y);

                    x += xDelta;
                    if (x >= bounds.x + bounds.width) {
                        x = bounds.x;
                        y += yDelta;
                    }
                }
            }

        }

    }

}

As you can see, this becomes real complicated real quick. This example currently only allows 4 players per cell, so if you want more, then you're going to have to create your own algorithim