How to use MouseListener to find a specific cell in a grid
Asked Answered
S

3

6

I'm trying to create a Java game with a 10 x 10 grid made up of cells. The Grid looks liks this:

public class Grid extends JPanel implements MouseListener {
    public static final int GRID_SIZE = 10;

    public Grid() {
        setPreferredSize(new Dimension(300, 300));
        setLayout(new GridLayout(GRID_SIZE, GRID_SIZE));

        for (int x = 0; x < GRID_SIZE; x++)
            for (int y = 0; y < GRID_SIZE; y++)
                add(new Cell(x, y));
        addMouseListener(this);
    }

// All Mouse Listener methods are in here.

The Cell class looks like this:

public class Cell extends JPanel {

    public static final int CELL_SIZE = 1;
    private int xPos;
    private int yPos;

    public Cell (int x, int y) {
        xPos = x;
        yPos = y;
        setOpaque(true);
        setBorder(BorderFactory.createBevelBorder(CELL_SIZE));
        setBackground(new Color(105, 120, 105));
        setPreferredSize(new Dimension(CELL_SIZE, CELL_SIZE));
    }

    // Getter methods for x and y.

My issue is that I am now trying to implement the MouseListeners in the Grid class. What I have realised is that whilst I can return the X and Y coordinates of the Grid, I can't seem to manipulate the cells themselves. I am assuming this is because when I created them in Grid, I am creating 100 random Cells with no identifiers and so I have no way to directly access them.

Could anybody give me advice on this? Do I need to overhaul my code and the way I am creating the cells? Am I being terribly stupid and missing an obvious way of accessing them? Thanks

Selfaddressed answered 24/4, 2013 at 13:11 Comment(0)
U
2

You could use an adapter pattern, as shown below. That way, you can add the listener to each grid cell individually, but still handle the events from Grid.

Note that Grid no longer implements MouseListener, this is handled by the cells now.

public class Grid extends JPanel {
    public static final int GRID_SIZE = 10;

    public Grid() {
        setPreferredSize(new Dimension(300, 300));
        setLayout(new GridLayout(GRID_SIZE, GRID_SIZE));

        for (int x = 0; x < GRID_SIZE; x++) {
            for (int y = 0; y < GRID_SIZE; y++) {
                final Cell cell = new Cell(x, y);
                add(cell);
                cell.addMouseListener(new MouseListener() {
                    public void mouseClicked(MouseEvent e) {
                        click(e, cell);
                    }
                    // other mouse listener functions
                });
            }
        }        
    }

    public void click(MouseEvent e, Cell cell) {
        // handle the event, for instance
        cell.setBackground(Color.blue);
    }

    // handlers for the other mouse events
}

A subclass could override this as:

public class EnemyGrid extends Grid {
    public void click(MouseEvent e, Cell cell) {
        cell.setBackground(Color.red);
    }
}
Uncap answered 24/4, 2013 at 13:17 Comment(10)
This is a really useful piece of code - thank you! Can I ask a follow up question - I actually create two subclasses out of Grid: OwnGrid and EnemyGrid. They both originally overrode the MouseListener methods that were contained in the Grid class. With the new structure that you have proposed, how could I override these methods in the Grid subclasses?Selfaddressed
@AndrewMartin I'm not sure if I understand that correctly, but if you want to handle the event differently in both subclasses, you can just override mouseClicked(MouseEvent e, Cell cell)Uncap
how could I override these methods in the Grid subclasses not this is not easy job(since is possible without any issue), you can to lost in JCOmponents hierarchy, one of disadvantage came from inheritance , use composition insteadEmeliaemelin
What I meant was this: Let's say I follow your method and make the mouseClicked method set the background yellow. In the subclass, I created a method called public void mouseClicked, which accepts the same parameters - MouseEvent and Cell. However, in this method I try and change the background color to red. Unfortunately, nothing happens. What could I do to fix this?Selfaddressed
@AndrewMartin I was a little unlucky with the name of the method. I renamed it to click and have no problem with overriding at all.Uncap
I followed the code down to adding the mouse listener, created the "new MouseListener()" and added all the necessary methods. I added two methods for each action. The first method "mouseClicked" overrides the MouseListener interface and calls the second method, sending the MouseEvent and cell as parameters. the second method ("click") takes both of these parameters and performs an action. In the subclass, I have the EXACT SAME second method ("click"), but it complains that it is not overriding anything and so doesn't do anything.Selfaddressed
@AndrewMartin note that click is not inside the MouseListener, but is just a method of Grid. Moreover, I removed the implements MouseListener from Grid because it is no longer needed (sorry for not mentioning that :-) )Uncap
Flipping eejit I am - I noticed the MouseListener not being implemented anymore, but had all my methods like click inside the MouseListener. As soon as I moved them outside, everything worked perfectly. You should probably make that totally explicit in your answer. Lots of idiots like me online these days!Selfaddressed
On a final note. Thanks for this answer. I've been stuck on this for hours and you've solved it for me in minutes. Honestly, thanks a million.Selfaddressed
@AndrewMartin tnx for the advise, I made the answer a little more elaborate. And yw of course :-)Uncap
E
2
Emeliaemelin answered 24/4, 2013 at 13:22 Comment(4)
Thanks for your answer and your comment on the other post. I am not really familiar with composition. I have gotten rid of the "extends" part of the subclass and have instead created done "private Grid grid = new Grid()" - how can I now connect this to mouseListeners etc?Selfaddressed
see another JButton and ActionListener, again change JButton to JPanel and ActionListener to MouseListener only, as general and working code exampleEmeliaemelin
I'd suggest to use putClientProperty for grid based games e.g. puzzle, sudoku, ....Emeliaemelin
Point taken. I'm trying to read up on it now. I've never used almost any of these constructs before!Selfaddressed
E
1

The most obvious way would be to move your MouseListener on the Cell class itself.

Second option I can think of is to use java.awt.Container.getComponentAt(int, int).

Expel answered 24/4, 2013 at 13:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.