0

I have a JPanel that contains a 16X16 GridLayout inside of a JLayeredPane and i've initialized the grid's cells in order to make the grid look like a board game. Now what i need to do, is be able to move the red and yellow pawns (numbers 1,2) around the outer parts of the grid and start/home areas. I tried removing the old component at a selected cell in the grid and then adding the pawn JButton to that cell (as you can see in the placePawnAt() method) but then the whole grid gets messed up (see 2nd image). I read some posts and i didn't find a solution yet other than people suggesting you use a GridBagLayout. Any ideas on how i can go about moving my JButton pawns around the grid?

I considered creating a JLabel[][] that will hold the JLabels of each cell and then i could simply swap components through the array and the grid would use the new component. However, my pawns are JButtons so i couldn't do it that way. Is there a way to place the pawns on top of a certain cell of the grid since this is a JLayeredPane instead of adding them in the grid's cells? And if so, how would i know to which point in the screen the pawn should move at in order to be directly on top of a selected cell ?

Here's the BoardPanel that extends JLayeredPane and contains the JPanel with the grid:

public class BoardPanel extends JLayeredPane {

    // Image resource declaration and initialization
    ImageIcon blueSlideEnd = new ImageIcon(getClass().getClassLoader().getResource("res/slides/blueSlideEnd.png"));
    ImageIcon blueSlideMid = new ImageIcon(getClass().getClassLoader().getResource("res/slides/blueSlideMedium.png"));
    ImageIcon blueSlideStart = new ImageIcon(getClass().getClassLoader().getResource("res/slides/blueSlideStart.png"));
    ImageIcon greenSlideEnd = new ImageIcon(getClass().getClassLoader().getResource("res/slides/greenSlideEnd.png"));
    ImageIcon greenSlideMid = new ImageIcon(getClass().getClassLoader().getResource("res/slides/greenSlideMedium.png"));
    ImageIcon greenSlideStart = new ImageIcon(getClass().getClassLoader().getResource("res/slides/greenSlideStart.png"));
    ImageIcon redSlideEnd = new ImageIcon(getClass().getClassLoader().getResource("res/slides/redSlideEnd.png"));
    ImageIcon redSlideMid = new ImageIcon(getClass().getClassLoader().getResource("res/slides/redSlideMedium.png"));
    ImageIcon redSlideStart = new ImageIcon(getClass().getClassLoader().getResource("res/slides/redSlideStart.png"));
    ImageIcon yellowSlideEnd = new ImageIcon(getClass().getClassLoader().getResource("res/slides/yellowSlideEnd.png"));
    ImageIcon yellowSlideMid = new ImageIcon(getClass().getClassLoader().getResource("res/slides/yellowSlideMedium.png"));
    ImageIcon yellowSlideStart = new ImageIcon(getClass().getClassLoader().getResource("res/slides/yellowSlideStart.png"));
    ImageIcon redPawnOne = new ImageIcon(getClass().getClassLoader().getResource("res/pawns/redPawn1.png"));
    ImageIcon redPawnTwo = new ImageIcon(getClass().getClassLoader().getResource("res/pawns/redPawn2.png"));
    ImageIcon yellowPawnOne = new ImageIcon(getClass().getClassLoader().getResource("res/pawns/yellowPawn1.png"));
    ImageIcon yellowPawnTwo = new ImageIcon(getClass().getClassLoader().getResource("res/pawns/yellowPawn2.png"));

    private JPanel boardGrid;
    private JButton redPawn1;
    private JButton redPawn2;
    private JButton yellowPawn1;
    private JButton yellowPawn2;

    // Constructor
    public BoardPanel() {
        setPreferredSize(new Dimension(650,690)); // set the size of the JLayeredPane
        boardGrid = new JPanel(new GridLayout(16,16)); // Set the layout manager of the JPanel to a GridLayout
        boardGrid.setSize(650,690); // set the size of the JPanel that contains the grid

        initializeGridCells(boardGrid);
        add(boardGrid,0); // add the JPanel that holds the grid to the JLayeredPane

        // Create the necessary non-grid related components
        JLabel logo = createLogo();
        RedRectangularJLabel redHomeArea = new RedRectangularJLabel("Home",Color.red, Color.white,55,255);
        RedRectangularJLabel redStartArea = new RedRectangularJLabel("Start",Color.red,Color.white,150,44);
        YellowRectangularJLabel yellowHomeArea = new YellowRectangularJLabel("Home",Color.yellow,Color.white,495,360);
        YellowRectangularJLabel yellowStartArea = new YellowRectangularJLabel("Start", Color.yellow,Color.white,400,572);
        JButton redPawn1 = createPawnButton(redPawnOne,165,65);
        JButton redPawn2 = createPawnButton(redPawnTwo,205,65);
        JButton yellowPawn1 = createPawnButton(yellowPawnOne,415,600);
        JButton yellowPawn2 = createPawnButton(yellowPawnTwo, 455, 600);
        // Add the components to the layered pane
        add(logo,1);
        add(redHomeArea,1);
        add(redStartArea,1);
        add(yellowHomeArea,1);
        add(yellowStartArea,1);
        add(redPawn1,2);
        add(redPawn2,2);
        add(yellowPawn1,2);
        add(yellowPawn2,2);
        // Move the non-grid components to the front of the layered pane to make them visible
        moveToFront(logo);
        moveToFront(redHomeArea);
        moveToFront(redStartArea);
        moveToFront(yellowHomeArea);
        moveToFront(yellowStartArea);
        moveToFront(redPawn1);
        moveToFront(redPawn2);
        moveToFront(yellowPawn1);
        moveToFront(yellowPawn2);
    }

    /**
     * Creates a JButton with the desired ImageIcon
     * at the desired position and some extra styling attributes.
     * @param pawnImg The ImageIcon to be used
     * @param x The x position
     * @param y The y position
     * @return The final stylized JButton
     */
    private JButton createPawnButton(ImageIcon pawnImg, int x , int y) {
        JButton pawn = new JButton();
        pawn.setIcon(pawnImg);
        pawn.setLocation(x,y);
        pawn.setSize(30,30);
        pawn.setOpaque(false);
        pawn.setBorder(new LineBorder(Color.black));
        return pawn;
    }

    /**
     * Initializes the cells of the grid with the appropriate
     * JComponents.
     * @param boardGrid The JPanel containing the GridLayout whose cells will be filled
     */
    private void initializeGridCells(JPanel boardGrid) {
        // Add the labels to the respective cells of the grid
        RotatableJLabel tile;
        for(int i = 0; i < 256; i++) {
            if((i < 16) || (i%16 == 0) || (i > 240) || (i%16 == 15)) { // initialize the outer tiles of the board
                if(i == 31 || i == 159) { // start of green slides
                    tile = new RotatableJLabel(greenSlideStart,180);
                } else if(i == 47 || i == 63 || i == 175 || i == 191 || i == 207) { // middle part(S) of green slides
                    tile = new RotatableJLabel(greenSlideMid,180);
                } else if(i == 79 || i == 223) { // end of green slides
                    tile = new RotatableJLabel(greenSlideEnd,180);
                } else if(i == 254 || i == 245) { // start of yellow slides
                    tile = new RotatableJLabel(yellowSlideStart,0);
                } else if(i == 253 || i == 252 || i == 242 || i == 244 || i == 243) { // middle part(s) of the yellow slides
                    tile = new RotatableJLabel(yellowSlideMid,0);
                } else if(i == 251 || i == 241) { // end of yellow slides
                    tile = new RotatableJLabel(yellowSlideEnd,0);
                } else if(i == 32 || i == 160) { // end of blue slides
                    tile = new RotatableJLabel(blueSlideEnd,180);
                } else if(i == 48 || i == 64 || i == 80 || i == 192 || i == 176) { // middle of blue slides
                    tile = new RotatableJLabel(blueSlideMid,180);
                } else if(i == 96 || i == 208) { // start of blue slides
                    tile = new RotatableJLabel(blueSlideStart,180);
                } else if(i == 1 || i == 10) { // start of red slides
                    tile = new RotatableJLabel(redSlideStart,0);
                } else if(i == 2 || i == 3 || i == 11 || i == 12 || i == 13) { // middle of red slides
                    tile = new RotatableJLabel(redSlideMid,0);
                } else if(i == 4 || i == 14) { // end of red slides
                    tile = new RotatableJLabel(redSlideEnd,0);
                }else { // simple tile
                    tile = new RotatableJLabel();
                    tile.setBackground(Color.white);
                    tile.setLabelBorder();
                }
            }  else if(i == 18 || i == 34 || i == 50 || i == 66 || i == 82) { // red home path tiles
                tile = new RotatableJLabel();
                tile.setBackground(Color.red);
                tile.setLabelBorder();
            } else if(i == 237 || i == 221 || i == 205 || i == 189 || i == 173) { // yellow home path tiles
                tile = new RotatableJLabel();
                tile.setBackground(Color.yellow);
                tile.setLabelBorder();
            } else { // all other tiles
                tile = new RotatableJLabel();
                tile.setBackground(Color.cyan);
            }
            boardGrid.add(tile, i); // add the label to the respective grid cell
        }
    }

    /**
     * Creates a JLabel with the logo
     * as its icon.
     * @return A JLabel with the logo icon
     */
    private JLabel createLogo() {
        JLabel logo = new JLabel();
        ImageIcon logoIcon = new ImageIcon(getClass().getClassLoader().getResource("res/sorryImage.png"));
        logo.setBounds(240,310,logoIcon.getIconWidth(),logoIcon.getIconHeight());
        logo.setIcon(logoIcon);
        return logo;
    }

    /**
     * Places the selected pawn to the desired position
     * on the grid.
     * @param cellIndex The index of the cell in the grid
     * @param frame The JFrame containing the grid
     */
    public void placePawnAt(int cellIndex, JFrame frame) {
        boardGrid.remove(cellIndex);
        boardGrid.add(redPawn1, cellIndex);
        frame.revalidate();
        frame.repaint();
    }
} 

Here's my main class which creates the JFrame containing the BoardPanel :

public class Controller {

    private static Square[] boardTiles = new Square[256];
    private static BoardPanel boardPanel;
    private static GameInfoPanel infoPanel;
    private static JFrame window;

    /**
     * Creates the JFrame that will accommodate all
     * of the other GUI components and makes it visible.
     */
    private static void createAndShowGUI() {
        window = new JFrame("Sorry! Game");
        ImageIcon appIcon = new ImageIcon(Controller.class.getClassLoader().getResource("res/icon.png")); // create the icon for the app
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when the 'X' button is clicked, the app stops
        window.setSize(new Dimension(1000, 750)); // setting the size of the window
        window.setResizable(false); // Window won't be resizable
        window.setIconImage(appIcon.getImage()); // set the icon for the app
        window.setLocationRelativeTo(null); // centers the window to the screen
        window.setLayout(new BorderLayout()); // set the jframe's layout to a border layout
        boardPanel = new BoardPanel(); // create a new BoardPanel Instance
        infoPanel = new GameInfoPanel(); // create a new GameInfoPanel instance
        window.add(infoPanel,BorderLayout.EAST); // add the info panel to the right side of the frame
        window.add(createMenu(),BorderLayout.NORTH); // add the menu bar to the top of the frame
        window.add(boardPanel,BorderLayout.WEST); // add the board (JLayeredPane) to the left of the frame
        window.setVisible(true); // make the window visible
    }

    //TODO:sp move this in a separate view class
    private static JMenuBar createMenu() {
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(new JMenu("New Game"));
        menuBar.add(new JMenu("Save Game"));
        menuBar.add(new JMenu("Continue Saved Game"));
        menuBar.add(new JMenu("Exit Game"));
        return menuBar;
    }

    private static void initializeBoardTiles(Square[] tiles) {
        for(int i = 0; i < 256; i++) {
            if((i < 16) || (i%16 == 0) || (i > 240) || (i%16 == 15)) { // initialize the outer tiles of the board
                if(i == 31 || i == 159) { // start of green slides
                    tiles[i] = new StartSlideSquare(Color.green,true);
                } else if(i == 47 || i == 63 || i == 175 || i == 191 || i == 207) { // middle part(S) of green slides
                    tiles[i] = new InternalSlideSquare(Color.green,true);
                } else if(i == 79 || i == 223) { // end of green slides
                    tiles[i] = new EndSlideSquare(Color.green,true);
                } else if(i == 254 || i == 245) { // start of yellow slides
                    tiles[i] = new StartSlideSquare(Color.yellow,true);
                } else if(i == 253 || i == 252 || i == 242 || i == 244 || i == 243) { // middle part(s) of the yellow slides
                    tiles[i] = new InternalSlideSquare(Color.yellow,true);
                } else if(i == 251 || i == 241) { // end of yellow slides
                    tiles[i] = new EndSlideSquare(Color.yellow,true);
                } else if(i == 32 || i == 160) { // end of blue slides
                    tiles[i] = new EndSlideSquare(Color.blue,true);
                } else if(i == 48 || i == 64 || i == 80 || i == 192 || i == 176) { // middle of blue slides
                    tiles[i] = new InternalSlideSquare(Color.blue,true);
                } else if(i == 96 || i == 208) { // start of blue slides
                    tiles[i] = new StartSlideSquare(Color.blue,true);
                } else if(i == 1 || i == 10) { // start of red slides
                    tiles[i] = new StartSlideSquare(Color.red,true);
                } else if(i == 2 || i == 3 || i == 11 || i == 12 || i == 13) { // middle of red slides
                    tiles[i] = new InternalSlideSquare(Color.red,true);
                } else if(i == 4 || i == 14) { // end of red slides
                    tiles[i] = new EndSlideSquare(Color.red,true);
                }else { // simple tile
                    tiles[i] = new SimpleSquare(Color.green,true);
                }
            }  else if(i == 18 || i == 34 || i == 50 || i == 66 || i == 82) { // red home path tiles
                    tiles[i] = new HomeSquare(Color.red,true);
            } else if(i == 237 || i == 221 || i == 205 || i == 189 || i == 173) { // yellow home path tiles
                    tiles[i] = new HomeSquare(Color.yellow,true);
            } else { // all other tiles
                tiles[i] = new NonTraversableSquare(Color.cyan);
            }
        }
    }

    public static void main(String[] args) {
        initializeBoardTiles(boardTiles);
        createAndShowGUI();
        //boardPanel.placePawnAt(5,window);
    }
}

Here's the layout so far without calling the placePawnAt method : currentLayout

And here's what i get if i use my faulty placePawnAt method : result

Stelios Papamichail
  • 955
  • 2
  • 19
  • 57
  • 1
    I've not read through your code, but, your basic concept isn't off. You "basically" want to move the component within the containers component list. See [this example](https://stackoverflow.com/questions/34585343/trying-to-move-jlabels-on-a-jpanel-with-gridlayout/34585504#34585504) and [this example](https://stackoverflow.com/questions/16834765/move-jbutton-with-keyboard-arrows-inside-a-grid-panel/16835242#16835242) for more details. Essentially you will need to fill the grid with components (I've use `JLabel`s as they are transparent) and then let the API swap them – MadProgrammer Nov 27 '19 at 21:09
  • 1
    Don't swap the component. Swap the content. General tips: 1) For better help sooner, [edit] to add a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). 2) One way to get image(s) for an example is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). E.G. [This answer](https://stackoverflow.com/a/10862262/418556) hot links to an image embedded in [this question](https://stackoverflow.com/q/10861852/418556). – Andrew Thompson Nov 27 '19 at 21:22
  • @MadProgrammer thank you very much for the links, they help tremendously with the logic. My issue though is that since the player is a JButton how can i move it through the component list since that list is made out of JLabels? I also don't think i should add the pawns into the grid since that would replace the background image of the respective tile and i would need to hold a reference to the old component of that tile, wouldn't i? Can i create a "fake" empty JLabel as the player, apply the logic of the posts you linked and then get that label's position in order to place the button on top? – Stelios Papamichail Nov 27 '19 at 23:43
  • It's a complex issue, made more complex by the fact that this isn't really how components are meant to be used. You might consider going down a custom painting route, which will give you more control over the placement of elements. You could even consider a custom layout manager which would allow you to control the placement of the components yourself, based on your custom needs – MadProgrammer Nov 28 '19 at 00:01
  • Sadly i don't have the knowledge or the time to make such custom components and layout managers. This is supposed to be a project for college but we only talked about java swing & awt in a single lecture. I wasn't expecting things to be so complicated since we only have 10 days to build this game and were told that the simple stuff we saw in the lecture would suffice. I'll see what i can manage to find, thank you so so much for your help and insight though :) – Stelios Papamichail Nov 28 '19 at 00:21

0 Answers0