Search code examples
javaswinguser-interfacechess

How to work with MouseListener. Don't work GUI


I am trying to write simple chess application based on this tutorial: https://proghammer.wordpress.com/2010/08/10/chess01-dragging-game-pieces/ I use this code with some changes, and it doesn't work. I am really new in Java GUI programming, can someone tell me what I do wrong.

UPDATE: I am trying to correct my mistakes, when I asked this question, I tryed to debug this. And I think that problem is in ChessGame class. Methods like mouseDragged() are working but nothing changed. Pieces did't drag. And I asking for helping with this. There is too much code, but this code only for providing full information. I repeat, I think that problem is in ChessGame or (maybe in ChessView), other code is only for understanding structure.

This is my code:

public class ChessView extends JPanel {

ChessBoard board;

private static final int BOARD_START_X = 220;
private static final int BOARD_START_Y = 120;

private static final int TILE_WIDTH = 45;
private static final int TILE_HEIGHT = 45;

private Image background;

public ChessView() {
    board = new ChessBoard();
    // load and set background image
    URL backgroundImg = getClass().getClassLoader().getResource("background.jpg");
    this.background = new ImageIcon(backgroundImg).getImage();


    // add mouse listeners to enable drag and drop
    ChessGame game = new ChessGame(board, this);
    this.addMouseListener(game);
    this.addMouseMotionListener(game);

    // create application frame and set visible
    //
    JFrame f = new JFrame();
    f.setVisible(true);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.add(this);
    f.setResizable(false);
    f.setSize(this.background.getWidth(null), this.background.getHeight(null));
}

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

@Override
protected void paintComponent(Graphics g) {
    g.drawImage(this.background, 0, 0, null);
    int row;
    for(int i = 0; i < board.getHeight(); i++) {
        for(int j = 0; j < board.getWidth(); j++) {
            Piece piece = board.getBoardAsArray()[i][j];
            if (piece.getClass() != EmptySquare.class) {
                if (piece.getColor() == other.Color.WHITE) {
                    if (piece.getClass() != Pawn.class) row = 7;
                    else row = 6;
                } else {
                    if (piece.getClass() != Pawn.class) row = 0;
                    else row = 1;
                }
                int x = BOARD_START_X + (TILE_WIDTH * j);
                int y = BOARD_START_Y + (TILE_HEIGHT * row);
                piece.setX(x);
                piece.setY(y);
                g.drawImage(piece.getImage(), x, y, null);

            }
        }
    }
}

public ChessBoard getBoard() {
    return board;
}
}

This is my Listener:

public class ChessGame implements MouseListener, MouseMotionListener {

private ChessBoard board;
private ChessView view;

private Piece dragPiece;
private int dragOffsetX;
private int dragOffsetY;


public ChessGame(ChessBoard board, ChessView chessGui) {
    this.board = board;
    this.view = chessGui;
}

@Override
public void mousePressed(MouseEvent e) {
    int x = e.getPoint().x;
    int y = e.getPoint().y;

    for(int i = 0; i < view.getBoard().getHeight(); i++) {
        for(int j = 0; j < view.getBoard().getWidth(); j++) {
            Piece piece = view.getBoard().getBoardAsArray()[i][j];
            if (piece.getClass() != EmptySquare.class) {
                if (mouseOverPiece(piece, x, y)) {
                    this.dragOffsetX = x - piece.getX();
                    this.dragOffsetY = y - piece.getY();
                    this.dragPiece = piece;
                    break;
                }
            }
        }
    }
}

/**
 * check whether the mouse is currently over this piece
 * @param piece the playing piece
 * @param x x coordinate of mouse
 * @param y y coordinate of mouse
 * @return true if mouse is over the piece
 */
private boolean mouseOverPiece(Piece piece, int x, int y) {
    return piece.getX() <= x
            && piece.getX()+piece.getWidth() >= x
            && piece.getY() <= y
            && piece.getY()+piece.getHeight() >= y;
}

@Override
public void mouseReleased(MouseEvent arg0) {
    this.dragPiece = null;
}

@Override
public void mouseDragged(MouseEvent evt) {
    if(this.dragPiece != null){
        this.dragPiece.setX(evt.getPoint().x - this.dragOffsetX);
        this.dragPiece.setY(evt.getPoint().y - this.dragOffsetY);
        this.view.repaint();
    }

}

@Override
public void mouseClicked(MouseEvent arg0) {}

@Override
public void mouseEntered(MouseEvent arg0) {}

@Override
public void mouseExited(MouseEvent arg0) {}

@Override
public void mouseMoved(MouseEvent arg0) {}

}

This is my board representation:

public class ChessBoard {
private Piece[][] board = new Piece[8][8];

private final int WIDTH = 8;
private final int HEIGHT = 8;

//Write a NullPiece class or contain nulls is 2-5 rows?
public ChessBoard () {
    setStartBoard(); //rewrite
}

public int getHeight() {
    return HEIGHT;
}

public int getWidth() {
    return WIDTH;
}

public Piece[][] getBoardAsArray() {
    return board;
}

public ArrayList<Piece> getBoardAsArrayList() {
    ArrayList<Piece> list = new ArrayList<Piece>();
     for (int i = 0; i < WIDTH; i++) {
         for (int j = 0; j < HEIGHT; j++) {
             list.add(board[i][j]);
         }
     }
    return list;
}

Piece firstWhiteRook = new Rook(Color.WHITE);
Piece secondWhiteRook = new Rook(Color.WHITE);
Piece firstWhiteKnight = new Knight(Color.WHITE);
Piece secondWhiteKnight = new Knight(Color.WHITE);
Piece firstWhiteBishop = new Bishop(Color.WHITE);
Piece secondWhiteBishop = new Bishop(Color.WHITE);
Piece whiteQueen = new Queen(Color.WHITE);
Piece whiteKing = new King(Color.WHITE);
Piece firstWhitePawn = new Pawn(Color.WHITE);
Piece secondWhitePawn = new Pawn(Color.WHITE);
Piece thirdWhitePawn = new Pawn(Color.WHITE);
Piece fourthWhitePawn = new Pawn(Color.WHITE);
Piece fifthWhitePawn = new Pawn(Color.WHITE);
Piece sixthWhitePawn = new Pawn(Color.WHITE);
Piece seventhWhitePawn = new Pawn(Color.WHITE);
Piece eighthWhitePawn = new Pawn(Color.WHITE);

Piece firstBlackRook = new Rook(Color.BLACK);
Piece secondBlackRook = new Rook(Color.BLACK);
Piece firstBlackKnight = new Knight(Color.BLACK);
Piece secondBlackKnight = new Knight(Color.BLACK);
Piece firstBlackBishop = new Bishop(Color.BLACK);
Piece secondBlackBishop = new Bishop(Color.BLACK);
Piece blackQueen = new Queen(Color.BLACK);
Piece blackKing = new King(Color.BLACK);
Piece firstBlackPawn = new Pawn(Color.BLACK);
Piece secondBlackPawn = new Pawn(Color.BLACK);
Piece thirdBlackPawn = new Pawn(Color.BLACK);
Piece fourthBlackPawn = new Pawn(Color.BLACK);
Piece fifthBlackPawn = new Pawn(Color.BLACK);
Piece sixthBlackPawn = new Pawn(Color.BLACK);
Piece seventhBlackPawn = new Pawn(Color.BLACK);
Piece eighthBlackPawn = new Pawn(Color.BLACK);


//TODO: make this more beautiful?
public void setStartBoard() {

    //set color for each piece

    //add all pieces to board
    board[0][0] = firstBlackRook;
    board[0][1] = firstBlackKnight;
    board[0][2] = firstBlackBishop;
    board[0][3] = blackQueen;
    board[0][4] = blackKing;
    board[0][5] = secondBlackBishop;
    board[0][6] = secondBlackKnight;
    board[0][7] = secondBlackRook;

    board[1][0] = firstBlackPawn;
    board[1][1] = secondBlackPawn;
    board[1][2] = thirdBlackPawn;
    board[1][3] = fourthBlackPawn;
    board[1][4] = fifthBlackPawn;
    board[1][5] = sixthBlackPawn;
    board[1][6] = seventhBlackPawn;
    board[1][7] = eighthBlackPawn;


    board[7][0] = firstWhiteRook;
    board[7][1] = firstWhiteKnight;
    board[7][2] = firstWhiteBishop;
    board[7][3] = whiteQueen;
    board[7][4] = whiteKing;
    board[7][5] = secondWhiteBishop;
    board[7][6] = secondWhiteKnight;
    board[7][7] = secondWhiteRook;

    board[6][0] =  firstWhitePawn;
    board[6][1] =  secondWhitePawn;
    board[6][2] =  thirdWhitePawn;
    board[6][3] =  fourthWhitePawn;
    board[6][4] =  fifthWhitePawn;
    board[6][5] =  sixthWhitePawn;
    board[6][6] =  seventhWhitePawn;
    board[6][7] = eighthWhitePawn;

    for(int i = 2; i < 6; i++) {
        for(int j = 0; j < 8; j++) {
            board[i][j] = new EmptySquare(Color.EMPTY);
        }
    }


}

}

This is my Piece implementation:

public class PieceImpl implements Piece {

private int x;

private int y;

private static final String NAME = ""; // Only for getName(). Don't use.

private Color color;

private Image image;

public PieceImpl(Color color) {
    this.color = color;
}

public void setColor(Color color) {
    this.color = color;
}

public Color getColor() {
    return color;
}

public Image getImage() {
    return image;
}

public void setImage(Image image) {
    this.image = image;
}

public String toString() {
    if (this.getColor() == Color.BLACK) {
        return "b" + NAME;
    } else {
        return "w" + NAME;
    }
}

public int getX() {
    return x;
}

public void setX(int x) {
    this.x = x;
}

public int getY() {
    return y;
}

public void setY(int y) {
    this.y = y;
}

public int getWidth() {
    return image.getWidth(null);
}

public int getHeight() {
    return image.getHeight(null);
}
}

This is example of king implementation:

public class King extends PieceImpl implements Piece{
private static final String NAME = "K";

public King(Color color) {
    super(color);
    if (this.getColor() == Color.WHITE) {
        URL urlToImage = getClass().getClassLoader().getResource("wk.png");
        setImage(new ImageIcon(urlToImage).getImage());
    } else if (this.getColor() == Color.BLACK) {
        URL urlToImage = getClass().getClassLoader().getResource("bk.png");
        setImage(new ImageIcon(urlToImage).getImage());
    }
}

public String toString() {
    if (this.getColor() == Color.BLACK) {
        return "b" + NAME;
    } else {
        return "w" + NAME;
    }
}

I represent color by enum class:

public enum Color {

BLACK("black", 0),
WHITE("white", 1),
EMPTY("empty", -1);

private final String name;
private final int id;

private Color(String name, int id) {
    this.name = name;
    this.id = id;
}

public String getName() {
    return this.name;
}

public int getID() {
    return this.id;
}

}

This is not only me code, as I say I am trying to study with tutorial. But I want to use my board representation. When I am running application, it's run, and I see the GUI, but mouse events don't work. Can someone tell me where I make a mistake, why mouse events don't work?


Solution

  • I feel from your comments and debugging information that you have shared is that your mouseListener is working perfectly. So the problem lies somewhere else. Studying your code I find that in your ChessView class' paintComponent method resigns the piece variable's x and y in the code :

    int x = BOARD_START_X + (TILE_WIDTH * j);
    int y = BOARD_START_Y + (TILE_HEIGHT * row);
    piece.setX(x);
    piece.setY(y);
    

    And draws it on the the board in position x and y. So this is basically undoing what you have done in your mouseListener :

    this.dragPiece.setX(evt.getPoint().x - this.dragOffsetX);
    this.dragPiece.setY(evt.getPoint().y - this.dragOffsetY);
    

    So you should have a way of setting the the piece in the board class' new location

    OR

    you should have a system to store the initial values of x and y for each piece and should not reset the x and y values in the paintComponent and should call

    g.drawImage(piece.getImage(), piece.getX(), piece.getY(), null);