Question

I am currently trying to create an application for a game called Carcassone, but I am having a problem using the JLayeredPane in conjunction with MouseAdapters.

Currently I have a JLayeredPane which contains a JPanel with a GridLayout which serves as the game board. Each cell of the GridLayout contains a JPanel which contains inside of it a JLabel to represent the tiles that go on the board. (An empty tile is just a JLabel with a black square as an image).

I added a custom mouse adapter (TileMouseAdapter) to the JLayeredPane which allows users to move tiles around the game board (mouse press - drag - release) or rotate tiles (mouse click). (To test click next tile button and move around the tile that appears, after you click the submit button the tile will no longer be draggable if it was a valid move). This all works perfectly as it should until I add the next part.

Now I want to add a separate JPanel to the JLayeredPane at the top of the screen. This section should hold the game pieces that players can place on the tiles. I also want the JPanel to hold the game pieces so that players can drag the pieces to the tiles. However, when I create this panel and add it to the JLayeredPane the mouse adapter from the previous section no longer works properly. For example, if you click on the bottom section of a tile it no longer recognizes that you are clicking on the tile. It will only select the tile if you click on the top half each tile. Moreover, if you click on the bottom of a tile, sometimes it will select the tile below. i.e. it seems as if the mechanism to select tiles seems to be shifted upwards by about half a tile. Can anyone figure out an explanation for this problem / a possible fix? Thanks!

The code below is the code that I used to create the JLayeredPane containing the JPanel for the board (myBoardPanel) as well as the panel for game pieces (makeMeeplePanel())

        private JLayeredPane makeBoardPanel() {
    JLayeredPane layeredPane = new JLayeredPane();
    layeredPane.setLayout(new BorderLayout());
    myBoardPanel = new CarcassoneBoardPanel(layeredPane);
    layeredPane.add(makeMeeplePanel(), BorderLayout.NORTH, JLayeredPane.DEFAULT_LAYER);
    layeredPane.add(myBoardPanel, BorderLayout.CENTER, JLayeredPane.DEFAULT_LAYER);

    TileMouseAdapter tileMouseAdapter = new TileMouseAdapter(layeredPane);
    //MeepleMouseAdapter meepleMouseAdapter = new MeepleMouseAdapter(layeredPane);

    layeredPane.addMouseListener(tileMouseAdapter);
    layeredPane.addMouseMotionListener(tileMouseAdapter);
    //layeredPane.addMouseListener(meepleMouseAdapter);
    //layeredPane.addMouseMotionListener(meepleMouseAdapter);
    return layeredPane; 
}

Here is my custom mouse adapter for the game board:

    package gui;
    import java.awt.Component;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import javax.swing.JLayeredPane;
    import javax.swing.JPanel;

    import tiles.*;

    public class TileMouseAdapter extends MouseAdapter {
private JLayeredPane myLayeredPane;
private CarcassoneBoardPanel myBoard;
private Tile dragLabel;
private JPanel clickedPanel;


public TileMouseAdapter(JLayeredPane layeredPane) {
    myLayeredPane = layeredPane;
    myBoard = (CarcassoneBoardPanel) layeredPane.getComponents()[1];
}

private void reset() {
    if (dragLabel != null) {
        myLayeredPane.remove(dragLabel);
        myLayeredPane.revalidate();
        myLayeredPane.repaint();
    }
    dragLabel = null;
    clickedPanel = null;
} 

@Override
public void mouseClicked(MouseEvent event) {
    clickedPanel = (JPanel) myBoard.getComponentAt(event.getPoint());
    if (clickedPanel == null) {
        reset();
        return;
    }
    Component[] components = clickedPanel.getComponents();
    if (!(components[0] instanceof Tile) || components[0] instanceof EmptyTile || !((Tile) components[0]).isDraggable()) {
        return;
    }

    dragLabel = (Tile) components[0];
    dragLabel.rotate();
    clickedPanel.revalidate();
    clickedPanel.repaint();
    reset();
}

@Override 
public void mousePressed(MouseEvent event) {
    clickedPanel = (JPanel) myBoard.getComponentAt(event.getPoint());
    System.out.println(event.getPoint());
    if (clickedPanel == null) {
        reset();
        return;
    }
    Component[] components = clickedPanel.getComponents();
    if (!(components[0] instanceof Tile) || (components[0] instanceof EmptyTile) || !((Tile) components[0]).isDraggable()) {
        return;
    }
    dragLabel = (Tile) components[0];
    clickedPanel.remove(dragLabel);
    clickedPanel.add(new EmptyTile(dragLabel.getRow(), dragLabel.getCol()));
    clickedPanel.revalidate();
    clickedPanel.repaint();

    int x = event.getPoint().x - dragLabel.getWidth() / 2;
    int y = event.getPoint().y - dragLabel.getHeight() / 2;
    dragLabel.setLocation(x, y);
    try {
        myLayeredPane.add(dragLabel, JLayeredPane.DRAG_LAYER);
        myLayeredPane.repaint();
    } catch (IllegalArgumentException e) {
        //TODO: deal with this? 
        //gives error for some unknown reason, but doesnt effect anything? ignore...dumb error cus jswing sucks
    }
}

@Override
public void mouseDragged(MouseEvent event) {
    if (dragLabel == null) {
        return;
    }
    int x = event.getPoint().x - dragLabel.getWidth() / 2;
    int y = event.getPoint().y - dragLabel.getHeight() / 2;
    dragLabel.setLocation(x, y);
    myLayeredPane.revalidate();
}

@Override
public void mouseReleased(MouseEvent event) {
    //TODO: make sure cannot place tile on already occupied panel...
    if (dragLabel == null || !dragLabel.isDraggable()) {
        return;
    }
    myLayeredPane.remove(dragLabel);
    myLayeredPane.revalidate();
    myLayeredPane.repaint();


    JPanel droppedPanel = (JPanel) myBoard.getComponentAt(event.getPoint());
    if (droppedPanel == null) {
        clickedPanel.removeAll();
        clickedPanel.add(dragLabel);
        clickedPanel.revalidate();
        reset();
        return;
    }

    dragLabel.setPosition(((Tile) droppedPanel.getComponents()[0]).getRow(), ((Tile) droppedPanel.getComponents()[0]).getCol());
    droppedPanel.removeAll();
    droppedPanel.add(dragLabel);
    droppedPanel.revalidate();
    reset();
}

}

Please let me know if you need anymore info / code. This is my first time using this site, so sorry if I do not provide enough explanation, etc... Thanks!

Was it helpful?

Solution

Your problem is here:

@Override
public void mouseClicked(MouseEvent event) {
    clickedPanel = (JPanel) myBoard.getComponentAt(event.getPoint());

event.getPoint() will return a Point relative to your layeredPane with which your mouse listener is registered. myBoard.getComponentAt() will return the component at the point relative to the myBoard component, which is within your layered pane at layeredPane.getComponents()[1].

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top