2

I have to make a Minesweeper GUI, but I cannot figure out how to make each button have it's own mouseAdapter. When I click a button, it changes every button on the screen instead of just the one I clicked. Can I have some pointers on how to do this?

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MinePanel extends JPanel 
{
    private final int ROWS = 10;
    private final int COLUMNS = 10;
    private int numOfMines;
    private double probability;
    private JLabel statusBar;
    private int minesLeft;
    private JButton Minefield[][];
    private boolean hasMine = false;
    private int curRow = 0;
    private int curCol = 0;
    private JButton cell;

    public MinePanel() 
    {
        setLayout(new GridLayout(10, 10));
        Minefield = new JButton[ROWS][COLUMNS];
        //menuStuff();
        buildButtonField();
    }

    //I will eventually want to create a menu, but it's extra credit so I'm going to
    //wait until I have a working program.
    public JMenuBar menuStuff()
    {
        JMenuBar menuBar = new JMenuBar();
        //add(menuBar);
        JMenu file = new JMenu("File");
        menuBar.add(file);
        JMenu edit = new JMenu("Edit");
        menuBar.add(edit);
        return menuBar;
    }

    //Adds one to the total number of mines.
    public void addMine()
    {
        numOfMines++;
    }

    //Removes one from the total number of mines.
    public void removeMine()
    {
        numOfMines--;
    }

    //Assigns a JButton the value of true or false, which represents whether or not it
    //it is a mine. Is this the correct way to do this?
    public boolean setMines(JButton button)
    {
        probability  = Math.random()*100;
        if(probability >= 80)
        {
            hasMine = true;
            addMine();
        }
        else
        {
            hasMine = false;
        }
        return hasMine;
    }

    //This is supposed to change the JButton that is clicked on to either a T
    //or an F, eventually this will reveal what the value of the button is
    //or place a flag down. I'm guessing I shouldn't have used a for loop, but I don't 
    //know how else to do it.
    private class MouseHandler extends MouseAdapter
    {
        public void mouseClicked(MouseEvent e)
        {
            for(int r=0; r<ROWS; r++)
            {
                for(int c=0; c<COLUMNS; c++)
                {
                    if(e.getButton() == 1)
                    {
                        Minefield[r][c].setText("T");
                    }
                    else if(e.getButton() == 3)
                    {
                        Minefield[r][c].setText("F");
                    }
                }
            }
        }
    }

    //This builds the "Minefield" with a ROWS*COLUMNS amount of buttons.
    //It works fine but I'm open to suggestions on a better way to do this.
    public void buildButtonField()
    {
        for(int r = 0; r < ROWS; r++)
        {
            curRow++;
            for(int c = 0; c < COLUMNS; c++)
            {
                Minefield[r][c] = new JButton((r+1) + ", " + (c+1));

                setMines(Minefield[r][c]);

                Minefield[r][c].addMouseListener(new MouseHandler());

                add(Minefield[r][c]);
                curCol++;
            }
        }
    }
}

Thanks in advance for any help you guys give! I'm going to class, so it could take me a bit to respond.

dsdouglous
  • 93
  • 2
  • 4
  • 9

1 Answers1

6

When a mouse event occurs, you're iterating over every single cell in the grid. First, get rid of the loops in your MouseHandler:

private class MouseHandler extends MouseAdapter
{
    public void mouseClicked(MouseEvent e)
    {
        if(e.getButton() == 1)
        {
            Minefield[r][c].setText("T");
        }
        else if(e.getButton() == 3)
        {
            Minefield[r][c].setText("F");
        }
    }
}

You can then add two parameters to your MouseHandler constructor for row and column so that each mouse handler knows which cell it's responsible for.

public class MouseHandler extends MouseAdapter
{
    public int r, c; // instance variables
    public MouseHandler(int r, int c)
    {
        this.r = r;
        this.c = c;
    }

    ... // above code here
}

Creating the object may look something like this: Minefield[r][c].addMouseListener(new MouseHandler(r,c));

You could alternatively find mouse coordinates when the event is raised to manually determine which cell was clicked, but that's very messy.

xikkub
  • 1,641
  • 1
  • 16
  • 28
  • +1, although I would suggest using `row` and `column` rather than `r` and `c`. Single-letter variable names never end well. – MirroredFate Feb 26 '14 at 01:56
  • When a method accepts two parameters named `r` and `c`, it's obvious, at least in my method of coding, that they represent row and column. Same with `x` and `y`. It also saves me typing, and is very handy when I make mistakes and have to delete / retype things. Different strokes for different folks. – xikkub Feb 26 '14 at 02:07
  • It might work (maybe) as long as you personally are maintaining the code. However, personal conventions don't work as well when you are developing with a team. [After all...](http://stackoverflow.com/questions/876089/who-wrote-this-programing-saying-always-code-as-if-the-guy-who-ends-up-maintai) – MirroredFate Feb 26 '14 at 02:12