简体   繁体   中英

Get click position in grid. Java Swing

I got this code witch creates a clickable grid that shows the mouse position, altough i am not able to get the position in the grid in where the mouse is clicked, trying to be both X and Y position. Any ideas?

This how the grid looks

Code:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.MatteBorder;

public class TestGrid02 {


public TestGrid02() {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
            }

            JFrame frame = new JFrame("Testing");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new BorderLayout());
            frame.add(new TestPane());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
}

public class TestPane extends JPanel {
    private static final int ROWS = 20;
    private static final int COLUMNS = 20;
    private static GridBagConstraints gbc;

    public TestPane() {
        setLayout(new GridBagLayout());

        gbc = new GridBagConstraints();
        for (int row = 0; row < ROWS; row++) {
            for (int col = 0; col < COLUMNS; col++) {
                gbc.gridx = col;
                gbc.gridy = row;
                CellPane cellPane = new CellPane();
                Border border = null;
                if (row < ROWS-1) {
                    if (col < COLUMNS-1) {
                        border = new MatteBorder(1, 1, 0, 0, Color.GRAY);
                    } else {
                        border = new MatteBorder(1, 1, 0, 1, Color.GRAY);
                    }
                } else {
                    border = new MatteBorder(1, 1, 1, 0, Color.GRAY);
                }
                cellPane.setBorder(border);
                add(cellPane, gbc);
            }
        }
    }
}

public class CellPane extends JPanel {

    private Color defaultBackground;

    public CellPane() {
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                defaultBackground = getBackground();
                setBackground(Color.RED);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                setBackground(defaultBackground);
            }
            @Override
            public void mouseClicked(MouseEvent e){
                //Here is where it is supposed to be
            }
        });
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(30, 30);
    }
}

} In the CellPane class, witch is intended to be the one that listens to the mouse it is supposed to be the function that i need, at the mouseClicked listener, however i have tried with e.getX() or e.getLocationOnScreen() and these values were changing everytime i click in the same grid.

Well, that looks familiar

So, the basic idea would be to pass in the cell it's coordinates (ie, row/column) value via the constructor, for example...

public class CellPane extends JPanel {

    private Color defaultBackground;
    
    private Point cellCoordinate;

    public CellPane(Point cellCoordinate) {
        this.cellCoordinate = cellCoordinate;
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                defaultBackground = getBackground();
                setBackground(Color.RED);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                setBackground(defaultBackground);
            }

            @Override
            public void mouseClicked(MouseEvent e) {
                //Here is where it is supposed to be
                System.out.println("Did click cell @ " + getCellCoordinate().x + "x" + getCellCoordinate().y);
            }
        });
    }

    public Point getCellCoordinate() {
        return cellCoordinate;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(30, 30);
    }
}

The cell itself doesn't really care, not does it have any reasonable information available to it to determine how it's been laid out, so your best bet is to "tell" it the information you want it to represent.

For me, I'd just pass in the GridBagLayout row/col information, for example...

gbc.gridx = col;
gbc.gridy = row;
CellPane cellPane = new CellPane(new Point(col, row));

This way you remove all concept (and the issues associated with it) of how the cell is laid out

This approach (using buttons and action listeners) is better IMO. It uses the getButtonRowCol method to return a string indicating the button's location in an array (the buttonArray ).

在此处输入图像描述

Use b.setBorderPainted(false); (uncomment that code line) to get rid of the borders around each button. Look to the values passed to the constructor of the GridLayout to remove the space between buttons.

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

public class GameGridLayout {

    int size = 40;
    int iconSize = 10;
    JButton[][] buttonArray = new JButton[size][size];
    ActionListener actionListener;
    JLabel output = new JLabel("Click somewhere on the GUI");

    GameGridLayout() {
        JPanel gui = new JPanel(new BorderLayout(2,2));
        gui.setBorder(new EmptyBorder(4,4,4,4));
        gui.add(output,BorderLayout.PAGE_END);
        JPanel gameContainer = new JPanel(new GridLayout(0,size,2,2));
        gui.add(gameContainer);
        actionListener = e -> output.setText(getButtonRowCol((JButton)e.getSource()));
        for (int ii=0; ii<size*size; ii++) {
            JButton b = getButton();
            gameContainer.add(b);
            buttonArray[ii%size][ii/size] = b;
        }
        JFrame f = new JFrame("GameGridLayout");
        f.add(gui);
        f.pack();
        f.setMinimumSize(f.getSize());
        f.setLocationByPlatform(true);
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        f.setVisible(true);
    }

    private String getButtonRowCol(JButton button) {
        StringBuilder sb = new StringBuilder();
        for (int xx=0; xx<size; xx++) {
            for (int yy=0; yy<size; yy++) {
                if (button.equals(buttonArray[xx][yy])) {
                    sb.append("User selected button at: ");
                    sb.append(xx+1);
                    sb.append(",");
                    sb.append(yy+1);
                    break;
                }
            }
        }
        return sb.toString();
    }

    private JButton getButton() {
        JButton b = new JButton();
        b.setIcon(new ImageIcon(
                new BufferedImage(iconSize,iconSize,BufferedImage.TYPE_INT_ARGB)));
        b.setRolloverIcon(new ImageIcon(
                new BufferedImage(iconSize,iconSize,BufferedImage.TYPE_INT_RGB)));
        b.setMargin(new Insets(0,0,0,0));
        //b.setBorderPainted(false);
        b.setContentAreaFilled(false);
        b.addActionListener(actionListener);
        return b;
    }

    public static void main(String[] args) {
        Runnable r = () -> new GameGridLayout();
        SwingUtilities.invokeLater(r);
    }
}

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