Search code examples
javaswingawtgrid-layout

How to get X and Y index of element inside GridLayout?


I am studying a java tutorial and saw that the way to find the x/y indexes of a JButton inside a GridLayout is to traverse a bidimensional array of buttons b which is associated to the layout and checking if

b[i][j] == buttonReference.

  @Override
  public void actionPerformed(ActionEvent ae) {
    JButton bx = (JButton) ae.getSource();
    for (int i = 0; i < 5; i++)
      for (int j = 0; j < 5; j++)
        if (b[i][j] == bx)
        {
          bx.setBackground(Color.RED);
        }
  }

Is there an easier way to get the X/Y indexes of a button?

Something like:

JButton button = (JButton) ev.getSource();
int x = this.getContentPane().getComponentXIndex(button);
int y = this.getContentPane().getComponentYIndex(button);

this being a GameWindow instance and ev the ActionEvent triggered when the user presses the button.

In this case it should get: x == 2, y == 1

@GameWindow.java:

package javaswingapplication;

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

public class GameWindow extends JFrame implements ActionListener
{
  JButton b[][] = new JButton[5][5];

  int v1[] = { 2, 5, 3, 7, 10 };
  int v2[] = { 3, 5, 6, 9, 12 };

  public GameWindow(String title)
  {
    super(title);

    setLayout(new GridLayout(5, 5));
    setDefaultCloseOperation(EXIT_ON_CLOSE );

    for (int i = 0; i < 5; i++)
      for (int j = 0; j < 5; j++)
      {
        b[i][j] = new JButton();
        b[i][j].addActionListener(this);
        add(b[i][j]);
      }
  }

  @Override
  public void actionPerformed(ActionEvent ae) {
    ((JButton)ae.getSource()).setBackground(Color.red);
  }
}

@JavaSwingApplication.java:

package javaswingapplication;

public class JavaSwingApplication {
  public static void main(String[] args) {
    GameWindow g = new GameWindow("Game");
    g.setVisible(true);
    g.setSize(500, 500);
  }
}

Solution

  • This example shows how to create a grid button that knows its location on the grid. The method getGridButton() shows how to obtain a button reference efficiently based on its grid coordinates, and the action listener shows that the clicked and found buttons are identical.

    GridButtonPanel

    package gui;
    
    import java.awt.EventQueue;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    /**
     * @see http://stackoverflow.com/questions/7702697
     */
    public class GridButtonPanel {
    
        private static final int N = 5;
        private final List<JButton> list = new ArrayList<JButton>();
    
        private JButton getGridButton(int r, int c) {
            int index = r * N + c;
            return list.get(index);
        }
    
        private JButton createGridButton(final int row, final int col) {
            final JButton b = new JButton("r" + row + ",c" + col);
            b.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    JButton gb = GridButtonPanel.this.getGridButton(row, col);
                    System.out.println("r" + row + ",c" + col
                        + " " + (b == gb)
                        + " " + (b.equals(gb)));
                }
            });
            return b;
        }
    
        private JPanel createGridPanel() {
            JPanel p = new JPanel(new GridLayout(N, N));
            for (int i = 0; i < N * N; i++) {
                int row = i / N;
                int col = i % N;
                JButton gb = createGridButton(row, col);
                list.add(gb);
                p.add(gb);
            }
            return p;
        }
    
        private void display() {
            JFrame f = new JFrame("GridButton");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(createGridPanel());
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    new GridButtonPanel().display();
                }
            });
        }
    }