Reputation: 4283
I was hoping to make the grid produced by the code below report x and y coordinates of the location of the mouse pointer relative to pnlGrid
when clicked. But wherever I clicked (before i added a JLayeredPane
), I got no coordinates except for when the mouse pointer was in the red area.
So I added several lines of code to make a JLayeredPane
and I get mouse coordinate output, but no grid lines as shown in second screen shot.
How do I get both grid lines AND report of mouse coordinates when any place in the grid is clicked?
package gridcellcoordinator;
import gbl.GBConstraints;
import static java.awt.Color.*;
import java.awt.Color;
import java.awt.Dimension;
import static java.awt.EventQueue.invokeLater;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import static javax.swing.JLayeredPane.DEFAULT_LAYER;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
import javax.swing.event.MouseInputAdapter;
public class GridCellCoordinator {
final static int
GRID_PANEL_BORDER_WIDTH = 5,
N = 11,
CELLSIZE = 40;
//static final JLayeredPane layer = new JLayeredPane();
static final JPanel panel = new JPanel();
static final int SM_CELL_BORDER_WIDTH = 1;
static LineBorder SMcellBorder = new LineBorder(BLACK,SM_CELL_BORDER_WIDTH);
static JTextField[][] cells = new JTextField[N][N];
static JFrame frame = new JFrame();
public GridCellCoordinator(){
makeGrid();
}
private void makeGrid(){
JPanel pnlGrid = new JPanel();
pnlGrid.setLayout(new GridLayout(N,N));
pnlGrid.setBackground(BLUE);
pnlGrid.setBorder(BorderFactory.createLineBorder(Color.red,GRID_PANEL_BORDER_WIDTH));
pnlGrid.setLayout(new GridLayout(N, N));
for(int i = 0 ; i < N ; i++)
for(int j = 0; j < N; j++){
cells[i][j] = new JTextField();
cells[i][j].setText("X");
cells[i][j].setPreferredSize(new Dimension(CELLSIZE,CELLSIZE));
cells[i][j].setHorizontalAlignment(JTextField.CENTER);
cells[i][j].setFocusTraversalKeysEnabled(false);
cells[i][j].setBorder(SMcellBorder);
cells[i][j].setOpaque(true);
pnlGrid.add(cells[i][j], new GBConstraints());
}
panel.addMouseListener(new MouseInputAdapter()
{
public void mousePressed (MouseEvent e){panelMousePressed (e);}
});
pnlGrid.setPreferredSize(new Dimension(N*(CELLSIZE + 1) + 2*GRID_PANEL_BORDER_WIDTH ,
N*(CELLSIZE + 1) + 2*GRID_PANEL_BORDER_WIDTH));
panel.add(pnlGrid);
panel.setVisible(true);
panel.setOpaque(true);
panel.setPreferredSize(pnlGrid.getPreferredSize());
panel.setVisible(true);
//layer.add(pnlGrid, DEFAULT_LAYER);
//layer.setPreferredSize(pnlGrid.getPreferredSize());
//layer.setVisible(true);
frame.add(panel);
frame.setSize(new Dimension(pnlGrid.getPreferredSize()));
frame.setVisible(true);
frame.pack();
System.out.println("pnlGrid component count: " + pnlGrid.getComponentCount());
System.out.println("computed dimension: " + (N*(CELLSIZE + 1) + 2*GRID_PANEL_BORDER_WIDTH));
System.out.println("pnlGrid pref size: " + pnlGrid.getPreferredSize());
System.out.println("layer pref size: " + layer.getPreferredSize());
System.out.println("panel pref size: " + panel.getPreferredSize());
}
public void panelMousePressed(MouseEvent e){
JOptionPane.showMessageDialog(null,"Pressed:" + e.getX() + " " + e.getY());
}
public static void main(String[] args) {
invokeLater(new Runnable() {
public void run() {
new GridCellCoordinator();
}
});
}
}
P.S. As is, the code produces the grid on the left but only gives coordinates inside the red border. Remove the comment bars on the 4 layer lines to get the coordinates but no gridlines. I'd like BOTH gridlines and coordinates.
Upvotes: 0
Views: 3112
Reputation: 347314
You could use something like this or this
However, to fix your code, you need to change your focus. Instead of attaching the MouseListener
to the pnlGrid
, you need to attach it to the text fields. The reason for this is mouse events are like rain drops, any component with an attached MouseListener
will act like an umbrella, preventing MouseEvents
from occurring on components that are visually below them
To translate a MouseEvent
from one component context to another, you can use SwingUtilities.convertMouseEvent
or SwingUtilities.convertPoint
For example...
import java.awt.Color;
import static java.awt.Color.BLACK;
import static java.awt.Color.BLUE;
import java.awt.Dimension;
import static java.awt.EventQueue.invokeLater;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class GridCellCoordinator {
final static int GRID_PANEL_BORDER_WIDTH = 5,
N = 11,
CELLSIZE = 40;
//static final JLayeredPane layer = new JLayeredPane();
static final JPanel panel = new JPanel();
static final int SM_CELL_BORDER_WIDTH = 1;
static LineBorder SMcellBorder = new LineBorder(BLACK, SM_CELL_BORDER_WIDTH);
static JTextField[][] cells = new JTextField[N][N];
static JFrame frame = new JFrame();
public GridCellCoordinator() {
makeGrid();
}
private void makeGrid() {
JPanel pnlGrid = new JPanel();
pnlGrid.setLayout(new GridLayout(N, N));
pnlGrid.setBackground(BLUE);
pnlGrid.setBorder(BorderFactory.createLineBorder(Color.red, GRID_PANEL_BORDER_WIDTH));
pnlGrid.setLayout(new GridLayout(N, N));
MouseListener mouseHandler = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
doMousePressed(e);
}
};
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
cells[i][j] = new JTextField() {
@Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
};
cells[i][j].setText("X");
cells[i][j].setPreferredSize(new Dimension(CELLSIZE, CELLSIZE));
cells[i][j].setHorizontalAlignment(JTextField.CENTER);
cells[i][j].setFocusTraversalKeysEnabled(false);
cells[i][j].setBorder(SMcellBorder);
cells[i][j].addMouseListener(mouseHandler);
pnlGrid.add(cells[i][j]);
}
}
panel.add(pnlGrid);
panel.setVisible(true);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public void doMousePressed(MouseEvent e) {
Point p = e.getPoint();
System.out.println("Source point = " + p + " within " + e.getComponent());
p = SwingUtilities.convertPoint(e.getComponent(), p, e.getComponent().getParent());
System.out.println("Converted point = " + p + " within " + e.getComponent().getParent());
}
public static void main(String[] args) {
invokeLater(new Runnable() {
public void run() {
new GridCellCoordinator();
}
});
}
}
You should avoid using setPreferredSize
and rely more overriding getPreferredSize
when you need to. See Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? for more details
Upvotes: 1
Reputation: 118704
Well, each individual edit widget is what's eating your mouse in the above example.
A normal Java table simply displays the table in a single panel, and then when it's clicked, it then creates a control at that time to handle the editing. So, it's not a large array of edit controls. That turns out to be rather inefficient.
So, the solution is "don't do what you're doing". Or use the layered pane as you've already tried.
Addenda:
The problem is that you have a collection of first class components, each with their own "little" rectangles, rather than a larger, singular component. That's the problem you're encountering. Swing is treating all of those Labels and individual things (because they are). They don't have any global context to readily report compared to their container. You'd have to extrapolate based on their local coordinates converted to a "global" coordinate within the larger panel.
Upvotes: 0