简体   繁体   中英

Checking which Jbutton (of multiple Jbuttons) was clicked

I am making a board game, 8X8 matrix that have 64 JButton s in a frame. So far my code goes like this:

public class Main {
static JFrame f  = new JFrame();;
static JButton btn;
static JButton btnTemp;


    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setLayout((new GridLayout(8,8)));//size of the board
    f.setTitle("ex");
    f.setSize(800,800);

for (int i=0;i<=7;i++)
    {
        for (int j = 0; j<=7;j++)
        {

            btn=new JButton();
            btn = new JButton(new SoliderW());  
            btn.setName("btn"+i+""+j);
            btn.setBackground(Color.BLACK); 
            btn.addActionListener(actionListener); // make a listener to the button
            f.add(btn);
            }

    }


    f.setVisible(true);

I am trying to tell which JButoon was clicked using this code:

Component[] components = f.getContentPane().getComponents();


    ActionListener actionListener = new ActionListener()
    {
      @Override
        public void actionPerformed(ActionEvent e)
         {
              System.out.println("Hello");
          }
     };

       for (Component component : components)
          {
               if (component instanceof JButton)
                  {
                  ((JButton) component).addActionListener(actionListener);
                  }
          }

Yet, I dont understand how to tell which Jbutton was clicked.

Let's start with static is not your friend and you should avoid using it, especially when you're trying to reference an instance across object boundaries.

You could...

Use Anonymous Classes , for example...

btn = new JButton();
btn = new JButton(new SoliderW());
btn.setName("btn" + i + "" + j);
btn.setBackground(Color.BLACK);
btn.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent evt) {
        // Do some work
    }
}); // make a listener to the button

But, to be honest, since btn is static , this isn't going to help you

You could...

Make use of the actionCommand property

ActionListener actionListener = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent evt) {
        String command = evt.getActionCommand();
        // Do more work
    }
};

//...

for (int i = 0; i <= 7; i++) {
    for (int j = 0; j <= 7; j++) {

        btn = new JButton();
        btn = new JButton(new SoliderW());
        btn.setName("btn" + i + "" + j);
        btn.setBackground(Color.BLACK);
        // Replace the text with something that will
        // uniquely identify this button
        btn.setActionCommand("some cell identifier");
        btn.addActionListener(actionListener); // make a listener to the button
        f.add(btn);
    }

}

You could...

Create a custom ActionListener which takes the required information so that it can make better decisions about what to do (and decouple it from the button itself)

public class CardActionListener implements ActionListener {
    private int row, col;

    public CardActionListener(int row, int col) {
        this.row = row;
        this.col = col;
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        // Do some work...
    }
}

//...

for (int i = 0; i <= 7; i++) {
    for (int j = 0; j <= 7; j++) {

        btn = new JButton();
        btn = new JButton(new SoliderW());
        btn.setName("btn" + i + "" + j);
        btn.setBackground(Color.BLACK);
        btn.addActionListener(new CardActionListener(i, j)); // make a listener to the button
        f.add(btn);
    }

}

You could...

And would my personal preference, make use of the Action API .

This is similar to the last suggestion, but creates a much more self contained unit of work, which is decoupled from the invoker.

public class CardAction extends AbstractAction {
    private int row, col;

    public CardAction(int row, int col) {
        this.row = row;
        this.col = col;
        putValue(Action.LARGE_ICON_KEY, new SoliderW());
    }

    @Override
    public void actionPerformed(ActionEvent evt) {
        // Do some work...
    }
    
}

//...

for (int i = 0; i <= 7; i++) {
    for (int j = 0; j <= 7; j++) {

        btn = new JButton(new CardAction(i, j));
        f.add(btn);
    }

}

What's important...

One of the things I'm trying towards is decoupling the action functionality from the button itself, so the action isn't dependent on the button, but on the is provided the information it needs to perform it's operations.

This is a core concept of "model-view-controller" and will make you code easier to maintain

You could also do this in the listener:

Object src = e.getSource();
if ( src instanceof JButton ) {
   System.out.println( "Button is: " + ((JButton)src).getName() );
}

But it would be better to put all of the buttons in an ArrayList and then just use int index = list.indexOf(src);

Implementing MVC Pattern as suggested by MadProgrammer can be done as follows:
Have a Model class that holds all the information that the view (gui) needs.
Have a View class that uses the model to displays gui.
Have a Controller class that controls the model and view.

The following mre demonstrates the use of MVC Pattern to achieve the functionality required.
For convenience and simplicity, the following code can be copy-pasted into one file called Main.java and run:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {

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

//used listen to changes in view
interface SelectionListener{

    void selected(int row, int column);
}

/*Model contains the information for the view and information from the view
 * as well as the logic.
 * The model is independent of the user interface.
 */
class Model {

    private final String[][] soliderNames;

    Model(int size){

        soliderNames = new String[size][size];

        for (int i=0 ; i<size  ; i++)  {
            for (int j=0; j<size ; j++) {
                soliderNames[i][j] = i+"-"+j;
            }
        }
    }

    int getNunberOfRows(){
        return soliderNames.length;
    }

    int getNunberOfColumns(){
        return soliderNames[0].length;
    }

    String getName(int row, int column) {
        return soliderNames[row][column];
    }
}

/*View only contains the user interface part*/
class View{

    private final JFrame f;
    private static final int W = 50, H = 50;

    View(Model model, SelectionListener selectionListener){

        int rows = model.getNunberOfRows();
        int cols = model.getNunberOfColumns();

        JPanel view = new JPanel(new GridLayout(rows, cols));
        for (int i=0 ; i < rows ; i++)  {
            for (int j = 0 ; j < cols ; j++)    {
                int finalI =i, finalJ = j;
                JButton btn = new JButton();
                btn = new JButton("-");
                btn.setPreferredSize(new Dimension(W,H));
                btn.setBackground(Color.BLACK);
                btn.addActionListener( a -> selectionListener.selected(finalI, finalJ));
                view.add(btn);
            }
        }

        f  = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setTitle("ex");
        f.add(view);
        f.pack();
    }

    void show(){
        f.setVisible(true);
    }
}

/* The controller controls the view and model.
 * Based on the user action, the Controller calls methods in the View and Model
 * to accomplish the requested action.
 */
class Controller implements SelectionListener {

    private static final int SIZE = 8;
    private final Model model;

    Controller(){
        model = new Model(SIZE);
        View view = new View(model, this);
        view.show();
    }

    @Override
    public void selected(int row, int column) {

        System.out.print("row: "+ row + "  column: "+ column + " clicked. ");
        System.out.println("Name is "+ model.getName(row, column));
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM