3

This is related to How to get X and Y index of element inside GridLayout? post and its answers.

For whatever reason none of them suggested to extend JButton to include its position in the grid and in associated array of buttons.

I have made the following illustration that simply displays button's coordinates when it's clicked.

Extended JButton:

package buttons_array;

import javax.swing.*;

@SuppressWarnings("serial")
public class ButtonWithCoordinates extends JButton {

    int coordX;
    int coordY;

    public ButtonWithCoordinates(String buttonText, int coordX, int coordY) {
        super(buttonText);
        this.coordX = coordX;
        this.coordY = coordY;
    }

    /**
     * @return the coordX
     */
    public int getCoordX() {
        return coordX;
    }

    /**
     * @return the coordY
     */
    public int getCoordY() {
        return coordY;
    }
}

sample GUI:

package buttons_array;

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

public class ButtonsArray implements ActionListener {

    private ButtonWithCoordinates buttons[][];
    private int nRows;
    private int nCols;

    private JFrame frame;
    private JPanel panel;

    public ButtonsArray(int x, int y) {
        if (x > 0 && y > 0) {
            nRows = x;
            nCols = y;
            buttons = new ButtonWithCoordinates[nRows][nCols];
            for (int i=0; i < nRows; ++i) {
                for (int j=0; j < nCols; ++j) {
                    buttons[i][j] = new ButtonWithCoordinates("        ", i, j);
                    buttons[i][j].addActionListener(this);
                }
            }
        } else {
            throw new IllegalArgumentException("Illegal array dimensions!!!");
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        // TODO Auto-generated method stub
        ButtonWithCoordinates button = (ButtonWithCoordinates) e.getSource();
        button.setText(button.getCoordX() + ", " + button.getCoordY());

    }

    public void GUI() {

        if (buttons == null) { throw new NullPointerException("Array is not initialized!!!"); }

        frame = new JFrame();
        panel = new JPanel();

        frame.setContentPane(panel);
        panel.setLayout(new GridLayout(nRows, nCols));
        for (int i=0; i < nRows; ++i) {
            for (int j=0; j < nCols; ++j) {
                panel.add(buttons[i][j]);
            }
        }

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);

    }

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new ButtonsArray(3, 5).GUI();
            }
        });         

    }

}

Now my questions:

  1. Have I been reinventing the wheel here? I mean, is there a more straightforward way to achieve the same?

  2. Is it in any way inferior to searching through the array each time we need to find the coordinates?

Community
  • 1
  • 1
PM 77-1
  • 12,933
  • 21
  • 68
  • 111
  • Will your buttons end up being the same width? – Paul Richter Jan 25 '14 at 04:42
  • 2
    it's inappropriate subclassing: a) no new functionality that evolves its button-ness b) highly brittle - a class should be in full control of guaranteeing its contstraints and your comp can't because it's someone else who adds it to a grid c) there are several ways to easily reach the same without subclassing d) ... – kleopatra Jan 25 '14 at 11:00
  • @Teeg - Yes, as long as `GridLayout` is used. – PM 77-1 Jan 25 '14 at 20:52
  • 1
    @kleopatra - `b` - it allows to use either `GridLayout` or `GridBagLayout`; `c` - care to give examples? – PM 77-1 Jan 25 '14 at 20:54

1 Answers1

1

The original version of this example used extension:

GridButton extends JButton

The updated version was predicated on the colloquy seen here. While extension may be appropriate in some contexts, a few alternatives are mentioned here; a client property is particularly convenient. Identifying a button from its grid coordinates is also easy:

private static final int N = 5;
List<JButton> list = new ArrayList<>();
…
private JButton getGridButton(int r, int c) {
    int index = r * N + c;
    return list.get(index);
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 1
    Thank you for your very informative answer. So which approach would you personally consider the most appropriate when dealing with an array of some descendants of `JComponent`? I also have one *unrelated* question to ask. You used `EventQueue.invokeLater(...)` in your example. Tutorials that I've seen want us to use `SwingUtilities.invokeLater(...)`. Is one any more suitable than the other? – PM 77-1 Jan 25 '14 at 21:08
  • `SwingUtilities.invokeLater()` "is just a cover for `java.awt.EventQueue.invokeLater()`." On design, see Bloch, [_op cit._](http://stackoverflow.com/a/4709813/230513), especially items 16 & 17 – trashgod Jan 25 '14 at 23:29