How to work with a specific element in GridLayout?

2019-08-10 00:04发布

问题:

I have a problem adding an icon to a spesific element(grid?) in gridlayout. My gridlayout contains 64 "bricks" which is intended to work as a chessboard.

My gridcode looks like this:

ChessBoard

public class SjakkBrett extends JFrame implements Config {

public ChessBoard() {

    setSize(800,800);
    setLayout(new GridLayout(BRICKS/ ROWS, 0) );

    for (int id = 0; id < BRICKS; id++)         
        add(new Brick(id)); 

    setVisible(true);

}

Config

public interface Config {
    public int ROWS= 8;
    public int BRICKS= 64;
}

My problem is that I can't seem to find a way to add icons to a specific brick in the board, such as setIcon(new ImageIcon("pawn.png")); because I don't know how to use the brick ID's I'm making.

Anyone who could help me out here?

回答1:

To answer your specific question:

List<Brick> bricks = new ArrayList<Brick>();

public ChessBoard() {

    setSize(800,800);
    setLayout(new GridLayout(BRICKS/ ROWS, 0) );

    for (int id = 0; id < BRICKS; id++) {
        Brick brick = new Brick(id);        
        add(brick); 
        bricks.add(brick);
    }

    setVisible(true);

}

public void setBrick(int id, int piece) {
    bricks.get(id).setPiece(piece);
}

To answer your unasked questions, let's think about a game of chess for a bit.

A chess board already has a notation. A typical first move is e4. Since a piece is not specified, that means a pawn. The only pawn that can move to e4 is the pawn sitting on e2. So, e4 is a shorthand way of saying "move the pawn from e2 to e4".

So, we have bricks (squares) that are arranged to make a board. We have pieces with the ability to move from one brick to another, according to rules that are different for each piece. We also have capture rules and rules for determining who wins.

All of these elements have to be present in the game as either objects or methods.

So, let's talk about objects.

We have a brick (square). We have a collection of bricks called a board. We have pieces.

These objects are interrelated. What they all have in common is the idea of location.

A brick is located in a specific spot (e2). A board needs to know how to translate a spot (e2) into something meaningful (row 1, column 4; assuming row 0, column 0 is the lower left corner). A piece needs to know where it's located (e2), where it can legally go (e3, e4), and where it will go (e4).

This should be enough to get you started.



回答2:

Adding labels with the icon would probably make it slightly easier to make moveable pieces to the game later I guess, but still I don't know how to add the labels to spesific ID's in the gridlayout. BRICKS is just getting it's information from Config, where it's declared(?) the value 64. Sorry if I use the wrong names and stuff here, but I'm way to fresh with java to actually work with it.

  • have look at put/getClientProperty, then any action/event from Keyboard or MouseXxxListener returns proper coordinates from the array of JLabels or JButtons

  • you can to multiple numbers of put/getClientProperty, there isn't any limits

  • I'd be to use JButton (implemented setXxxIcon in API) instead of JLabel (there required call for repaint() for MouseMotionListener)



回答3:

Ive had this code lying around which I used as foundation to my own chess game.

Basically consists of 6 classes:

  • Test basically holds main and creates the GUI as well as loading a single piece to the chessboard.
  • NotationPanel which is used for row and coloumns to be shown on the side of the board.
  • Chessboard which holds all the ChessboardBlocks which make up the board also lays out the board with black and white labels in their appropriate locations.
  • ChessboardBlock which has a set location(i.e A4 etc) and can hold a ChessPiece instance.
  • ChessPiece which holds data/image of the Piece instance.
  • ChessPieceMouseAdapter to handle dragging and dropping of Pieces:

The output from a typical move:

From Location: A1 Piece Type: knight Piece Color: White

To Location: D3 Piece Type: knight Piece Color: White

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.*;

public class Test {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

                ChessPieceMouseAdapter chessPieceMouseAdapter = new ChessPieceMouseAdapter() {
                    @Override
                    boolean chessPieceSelected(ChessPiece chessPiece, ChessboardBlock cb) {
                        System.out.println("From Location: " + chessPiece.getLocation()
                                + " Piece Type: " + chessPiece.getType()
                                + " Piece Color: " + chessPiece.getColor());
                        return true;
                    }

                    @Override
                    void chessPiecePlaced(ChessPiece chessPiece, ChessboardBlock cb) {
                        cb.setPiece(new ChessPiece(chessPiece.getImage(),
                                chessPiece.getType(),
                                cb.getBlockLocation(),
                                chessPiece.getColor()));

                        System.out.println("To Location: " + cb.getChessPiece().getLocation()
                                + " Piece Type: " + cb.getChessPiece().getType()
                                + " Piece Color: " + cb.getChessPiece().getColor());
                    }
                };

                Chessboard chessBoard = new Chessboard(chessPieceMouseAdapter);
                chessPieceMouseAdapter.setChessboard(chessBoard);//or else NPE will be thrown when press/drag/release on chessboard occurs

                BufferedImage knightImage = null;
                try {
                    knightImage = ImageIO.read(new URL("http://i.stack.imgur.com/qdppY.png"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                ChessPiece knightPiece = new ChessPiece(knightImage, "Knight", null, "White");//location parameter can be null or anything will be set if matching block is found
                chessBoard.setChessPiece("A1", knightPiece);

                NotationPanel rows = new NotationPanel(new String[]{"8", "7", "6", "5", "4", "3", "2", "1"}, NotationPanel.VERTICAL);
                NotationPanel cols = new NotationPanel(new String[]{"A", "B", "C", "D", "E", "F", "G", "H"}, NotationPanel.HORIZONTAL);

                frame.add(rows, BorderLayout.WEST);
                frame.add(cols, BorderLayout.SOUTH);
                frame.add(chessBoard);

                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

class NotationPanel extends JPanel {

    final static String HORIZONTAL = "horizontal";
    final static String VERTICAL = "vertical";

    public NotationPanel(String[] strings, String direction) {
        if (direction.equals(VERTICAL)) {
            setLayout(new GridLayout(8, 0));
        } else {
            setLayout(new GridLayout(0, 8));
        }
        for (String string : strings) {
            this.add(new JLabel(string, JLabel.CENTER));
        }

    }
}

class Chessboard extends JPanel {

    private final ArrayList<ChessboardBlock> chessBoardBlocks;
    ChessPieceMouseAdapter chessPieceMouseAdapter;

    public Chessboard(ChessPieceMouseAdapter chessPieceMouseAdapter) {
        super(new GridLayout(8, 8));
        chessBoardBlocks = new ArrayList<>(64);
        layoutBoard();
        this.chessPieceMouseAdapter = chessPieceMouseAdapter;
        addMouseListener(this.chessPieceMouseAdapter);
        addMouseMotionListener(this.chessPieceMouseAdapter);
    }

    private void layoutBoard() {
        String[] cols = new String[]{"A", "B", "C", "D", "E", "F", "G", "H"};
        int[] rows = new int[]{1, 2, 3, 4, 5, 6, 7, 8};
        int NUMBER_OF_BLOCKS = 64;
        String row, col;
        int rowCount = 7, colCount = 0, trigger = 8;

        for (int i = 0; i < NUMBER_OF_BLOCKS; i++) {
            if (trigger == 0) {
                colCount = 0;
                trigger = 8;
                rowCount--;
            }
            col = cols[colCount++];
            row = String.valueOf(rows[rowCount]);
            trigger--;

            Color pieceHolderColor = ((rowCount + colCount) % 2 == 0 ? Color.WHITE : Color.BLACK);
            String pieceHolderLocation = col + row;

            ChessboardBlock pieceHolder = new ChessboardBlock(pieceHolderLocation, pieceHolderColor);
            pieceHolder.setPiece(null);

            add(pieceHolder);//add to the board
            chessBoardBlocks.add(pieceHolder);//add to piece holder array
        }
    }

    boolean setChessPiece(String location, ChessPiece piece) {
        for (int i = 0; i < chessBoardBlocks.size(); i++) {
            if (chessBoardBlocks.get(i).getBlockLocation().equalsIgnoreCase(location)) {
                chessBoardBlocks.get(i).setPiece(new ChessPiece(piece.getImage(),
                        piece.getType(), chessBoardBlocks.get(i).getBlockLocation(),
                        piece.getColor()));
                return true;
            }
        }
        return false;
    }

    public ArrayList<ChessboardBlock> getChessBoardBlocks() {
        return chessBoardBlocks;
    }

    @Override
    protected void paintChildren(Graphics g) {
        super.paintChildren(g);

        if (chessPieceMouseAdapter.isDragging()) {
            if (chessPieceMouseAdapter.getDraggedPiece() != null) {
                Graphics2D g2d = (Graphics2D) g;
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

                g2d.drawImage(chessPieceMouseAdapter.getDraggedPiece().getImage(),
                        chessPieceMouseAdapter.getDraggedPieceLocation().x, chessPieceMouseAdapter.getDraggedPieceLocation().y, this);
            }
        }
    }
}

class ChessboardBlock extends JLabel {

    private final Dimension labelDimensions = new Dimension(50, 50);
    private ChessPiece chessPiece;
    private String location;

    public ChessboardBlock(String location, Color backgroundColor) {
        //super(location,JLabel.CENTER);//puts location as text on label
        this.location = location;
        setBackground(backgroundColor);
        setOpaque(true);
    }

    @Override
    public Dimension getPreferredSize() {
        return labelDimensions;
    }

    void setPiece(ChessPiece p) {
        this.chessPiece = p;
        if (chessPiece == null) {
            setIcon(null);
        } else if (chessPiece.getImage() != null) {
            setIcon(new ImageIcon(chessPiece.getImage()));
        }
    }

    String getBlockLocation() {
        return location;
    }

    public ChessPiece getChessPiece() {
        return chessPiece;
    }
}

class ChessPiece {

    private BufferedImage image;
    private String location;
    private String type;
    private final String color;

    public ChessPiece(BufferedImage image, String type, String location, String color) {
        this.image = image;
        this.type = type;
        this.location = location;
        this.color = color;
    }

    public ChessPiece(ChessPiece p) {
        this.image = p.getImage();
        this.type = p.getType();
        this.location = p.getLocation();
        this.color = p.getColor();
    }

    public String getLocation() {
        return location;
    }

    public String getColor() {
        return color;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public BufferedImage getImage() {
        return image;
    }

    String getType() {
        return type;
    }
}

abstract class ChessPieceMouseAdapter extends MouseAdapter {

    private Chessboard chessboard;
    private ChessPiece draggedChessPiece;
    private boolean dragging;
    private Rectangle pieceRectangle;
    private Point draggedPieceInitialLocation;
    private Point pressedPoint;

    public ChessPieceMouseAdapter() {
        dragging = false;
        draggedPieceInitialLocation = new Point();
        pressedPoint = new Point();
    }

    public Point getDraggedPieceLocation() {
        return new Point(pieceRectangle.x, pieceRectangle.y);
    }

    public ChessPiece getDraggedPiece() {
        return draggedChessPiece;
    }

    @Override
    public void mousePressed(MouseEvent me) {
        pressedPoint = me.getPoint();
        ArrayList<ChessboardBlock> chessBoardBlocks = chessboard.getChessBoardBlocks();
        for (int i = 0; i < chessBoardBlocks.size(); i++) {
            if (chessBoardBlocks.get(i).getChessPiece() != null) {
                pieceRectangle = chessBoardBlocks.get(i).getBounds();
                if (pieceRectangle.contains(pressedPoint)) {
                    ChessPiece chessPiece = chessBoardBlocks.get(i).getChessPiece();
                    if (chessPieceSelected(chessPiece, chessBoardBlocks.get(i))) {
                        draggedChessPiece = new ChessPiece(chessPiece);
                        chessBoardBlocks.get(i).setPiece(null);

                        draggedPieceInitialLocation.x = pieceRectangle.x;
                        draggedPieceInitialLocation.y = pieceRectangle.y;

                        dragging = true;
                        chessboard.repaint();
                    }
                    break;
                }
            }
        }
    }

    @Override
    public void mouseReleased(MouseEvent me) {

        ArrayList<ChessboardBlock> chessBoardBlocks = chessboard.getChessBoardBlocks();
        for (int i = 0; i < chessBoardBlocks.size(); i++) {
            pieceRectangle = chessBoardBlocks.get(i).getBounds();
            if (pieceRectangle.contains(me.getPoint())) {
                if (draggedChessPiece != null) {
                    chessPiecePlaced(draggedChessPiece, chessBoardBlocks.get(i));
                }
            }
        }
        dragging = false;
        draggedChessPiece = null;
        chessboard.repaint();
    }

    @Override
    public void mouseDragged(MouseEvent me) {
        dragging = true;
        pieceRectangle.x = me.getX() - (pressedPoint.x - draggedPieceInitialLocation.x);
        pieceRectangle.y = me.getY() - (pressedPoint.y - draggedPieceInitialLocation.y);
        chessboard.repaint();
    }

    boolean isDragging() {
        return dragging;
    }

    abstract boolean chessPieceSelected(ChessPiece chessPiece, ChessboardBlock cb);

    abstract void chessPiecePlaced(ChessPiece chessPiece, ChessboardBlock cb);

    void setChessboard(Chessboard chessBoard) {
        this.chessboard = chessBoard;
    }
}


回答4:

First of all you have new GridLayout(BRICKS/ ROWS, 0) which shows you are setting layout to have 0 Columns. (The API specifies GridLayout(int rows, int cols))

As for the problem with finding the x, y coords, you don't need to. If you have a placeholders (i.e. custom labels) you can set the background color to correspond to the board cell and hold the image in the cell. The images can be set on top of the background that way for the chess look and feel. Have click events on the labels so that when the user clicks the label is does whatever you need it to do (move a piece to/from one cell to the other, player takes a piece, checks the board for mate/check mate, etc.)

You could implement the MouseListener's mousePressed and mouseReleased methods on the labels to get the desired start and end labels and if you want drag and drop functionality maybe implement MouseMotionListener's mouseDragged method and a custom paint method to the board (not labels).