Drag and Drop of Chess Pieces

Greetings.

In my chess program my chessboard is a JPanel with a mouseListener on it. I have implemented drag and drop of the pieces as follows…

  1. mousePressed to pick up a piece.
  2. mouseDragged to move a piece, with appropriate calls to repaint()
  3. mouseReleased to place a piece on a new square.
  4. mouseExited to prevent a piece from being dragged off the board.

Everything works fine, but I am not totally satisfied with item 4.

As it works now, as soon as the mouse reaches the edge of the board, if a piece is being dragged it is automatically placed back on its original square, without the mouseButton being released. Also the repaint doesn’t remove the piece being moved from where it left the board, until a subsequent repaint, but that is a small thing that I am not concerned with right now.

Anyways, I have seen programs where you can pick up a piece and drag it off the board, and if you release the mouse button while the pointer is off the board, then the piece will return to the original square. I can’t figure out how to do that, as how can the application generate a mouseReleased event if the mouse is not over the application for which the mouseListener is defined? See What I mean?

Thanks.

The events for release and so on to do with what application has focus (is active) and not where the mouse is currently located.
Just make a check if the mouse is at a valid position when released (inside the bounds of the jpanel) and if not teleport the chess piece back to it’s original position.

Instead of doing 4 with mouseExited, you should just clamp the values you use within mouseDragged as the drag happens.


public void mouseDragged(MouseEvent e)
{
    piecePos.x = e.getX();
    piecePos.y = e.getY();

    //Clamp the X to the maximum X of the board (usually its width plus its X position).
    piecePos.x = Math.min(piecePos.x, board.maxX);
    //Clamp the Y to the minimum Y of the board (usually 0 or the board's X position).
    piecePos.x = Math.max(piecePos.x, board.minX);

    //Clamp the Y to the maximum Y of the board (usually its height plus its Y position).
    piecePos.y = Math.min(piecePos.y, board.maxY);
    //Clamp the Y to the minimum Y of the board (usually 0 or the board's Y position).
    piecePos.y = Math.max(piecePos.y, board.minY);

    panel.repaint();
}

Thanks, I’ll give both ideas a try in the next couple of days and let you know how it goes.

I must say though, with regards to the first response, I don’t quite see how the issue of focus could be relevant. After all if the last thing I do is click on the board in order to start dragging a piece, then how is it that the board (JPanel) would lose the focus required to detect the mouse release. Unless… the high level container class is supposed to be acting as the mouse listener for events like that?

What I meant was simply that you shouldn’t have to worry about the mouse release not being fired off just because you’re outside the application. On the other hand I don’t use JPanels a lot so if it isn’t registered it might indeed be an idea to use the highest level container for the mouse listener.

Yeah, I’m beginning to see that that is the case, as I rewrite my chessboard class. It’s as if the xy co-ordinate space extends past the dimensions of the JPanel, which makes for some interesting moves on the chessboard, whereby the piece is dragged off and released on one side of the board, and re-appears on the other side of the board, except at the next row down. I’m not sure how I managed to overlook that fact before.

regards

Decorated portions of windows in Swing still count for coordinates, so it’s not a good idea to use the JFrame as a mouse listener. You should use wherever it is that you do your drawing. This is because you want the coordinates of your mouse to be in the same local space as the drawings, or you have to constantly worry about translating them which doesn’t make much sense to do.

Yeah that makes sense. And that’s the way I’ve always done it. Anyways, I’m gonna try your ideas about clamping, but before I do I wanna see what effect my chess move legality code has on this situation. Just for curiosity sake, it won’t be the final solution, cause I don’t want to run a move legality check on a move that isn’t even on the board.

regards.

Actually, I ended up adding the following code to my mouseReleased method, which achieves the effect that I wanted all along. I guess the point I originally missed was that the (x,y) co-ordinate system of the JPanel extends in all directions past the boundaries of the panel.

Thanks for the help.


if( (x >= width) || (y >= width) || (x <= 0) || (y <=0 ) ) {
    // return piece to original square and call repaint()
}

I’m glad it ended up working for you. In general it’s good to clamp (or bounds check like you did) values like that, even if you think there’s no way to get out of the bounds. If you’re not catching exceptions then one weird resolution issue or whatever can break the entire program. Usually when I have array access stuff I just throw out requests that are beyond bounds.

Yeah, I can see that your method is better, in the sense that it captures the “bad” event sooner. Without actually trying your idea, what I visualize is the piece staying within visual range, along the border of the panel, and even though the mouse pointer is no longer “on the piece”, the piece would still have vertical movement if the pointer is off to the right of the board.

Actually, if my interpretation of your clamping idea is correct, then I think there is a problem. If I drag the mouse off the board, then the game still thinks the piece is on the board, So if the clamped piece stays on a square that represents a legal move, then you may end up being forced into a legal move that you had no intention of making, See what I mean?