如何在面板内创建一个网格(带有网格线),并在单击任何网格单元格时让鼠标侦听器提供相对于面板的坐标?
How do I make a grid (with gridlines) inside a panel and have a mouse listener give coordinates relative to the panel when any grid cell is clicked?
我希望让下面的代码生成的网格在单击时报告鼠标指针相对于 pnlGrid
位置的 x 和 y 坐标。但是无论我点击哪里(在我添加 JLayeredPane
之前),我都没有得到任何坐标,除非鼠标指针位于红色区域。
所以我添加了几行代码来制作 JLayeredPane
我得到了鼠标坐标输出,但是没有网格线,如第二个屏幕截图所示。
如何在单击网格中的任何位置时同时获取网格线和鼠标坐标报告?
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。照原样,代码在左侧生成网格,但仅给出红色边框内的坐标。删除 4 层线上的注释栏以获取坐标但没有网格线。我想要网格线和坐标。
好吧,在上面的示例中,每个单独的编辑小部件都在占用您的鼠标。
一个普通的 Java table 只是在一个面板中显示 table,然后当它被点击时,它会在那时创建一个控件来处理编辑。因此,它不是大量的编辑控件。结果证明这是相当低效的。
所以,解决方案是"don't do what you're doing"。或者使用您已经尝试过的分层窗格。
附录:
问题是您有第一个 class 个组件的集合,每个组件都有自己的 "little" 个矩形,而不是一个更大的单一组件。这就是你遇到的问题。 Swing 正在处理所有这些标签和个别事物(因为它们是)。与他们的容器相比,他们没有任何全局上下文可以轻松报告。您必须根据它们在较大面板内转换为 "global" 坐标的本地坐标进行推断。
你可以使用 this or this
但是,要修复您的代码,您需要改变您的关注点。您不需要将 MouseListener
附加到 pnlGrid
,而是将其附加到文本字段。这样做的原因是鼠标事件就像雨滴,任何附加 MouseListener
的组件都会像一把伞一样,防止 MouseEvents
发生在视觉上位于它们下方的组件上
要将 MouseEvent
从一个组件上下文转换为另一个组件上下文,您可以使用 SwingUtilities.convertMouseEvent
or SwingUtilities.convertPoint
例如...
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();
}
});
}
}
您应该避免使用 setPreferredSize
并在需要时更多地依赖 getPreferredSize
。有关详细信息,请参阅 Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
我希望让下面的代码生成的网格在单击时报告鼠标指针相对于 pnlGrid
位置的 x 和 y 坐标。但是无论我点击哪里(在我添加 JLayeredPane
之前),我都没有得到任何坐标,除非鼠标指针位于红色区域。
所以我添加了几行代码来制作 JLayeredPane
我得到了鼠标坐标输出,但是没有网格线,如第二个屏幕截图所示。
如何在单击网格中的任何位置时同时获取网格线和鼠标坐标报告?
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。照原样,代码在左侧生成网格,但仅给出红色边框内的坐标。删除 4 层线上的注释栏以获取坐标但没有网格线。我想要网格线和坐标。
好吧,在上面的示例中,每个单独的编辑小部件都在占用您的鼠标。
一个普通的 Java table 只是在一个面板中显示 table,然后当它被点击时,它会在那时创建一个控件来处理编辑。因此,它不是大量的编辑控件。结果证明这是相当低效的。
所以,解决方案是"don't do what you're doing"。或者使用您已经尝试过的分层窗格。
附录:
问题是您有第一个 class 个组件的集合,每个组件都有自己的 "little" 个矩形,而不是一个更大的单一组件。这就是你遇到的问题。 Swing 正在处理所有这些标签和个别事物(因为它们是)。与他们的容器相比,他们没有任何全局上下文可以轻松报告。您必须根据它们在较大面板内转换为 "global" 坐标的本地坐标进行推断。
你可以使用 this or this
但是,要修复您的代码,您需要改变您的关注点。您不需要将 MouseListener
附加到 pnlGrid
,而是将其附加到文本字段。这样做的原因是鼠标事件就像雨滴,任何附加 MouseListener
的组件都会像一把伞一样,防止 MouseEvents
发生在视觉上位于它们下方的组件上
要将 MouseEvent
从一个组件上下文转换为另一个组件上下文,您可以使用 SwingUtilities.convertMouseEvent
or SwingUtilities.convertPoint
例如...
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();
}
});
}
}
您应该避免使用 setPreferredSize
并在需要时更多地依赖 getPreferredSize
。有关详细信息,请参阅 Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?