如何在面板内部制作网格(带网格线)并让鼠标监听器在单击任何网格单元格时提供相对于面板的坐标?

时间:2015-03-23 21:57:07

标签: java swing grid-layout mouselistener jlayeredpane

我希望通过以下代码生成网格,在单击时报告鼠标指针相对于pnlGrid位置的x和y坐标。但无论我在哪里点击(在我添加JLayeredPane之前),我都没有坐标,除非鼠标指针位于红色区域。

所以我添加了几行代码来制作JLayeredPane并获得鼠标坐标输出,但没有网格线,如第二次屏幕截图所示。

如果点击网格中的任何位置,如何同时获取网格线和鼠标坐标报告?

enter image description here

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层线上的注释栏以获取坐标但没有网格线。我喜欢BOTH网格线和坐标。

2 个答案:

答案 0 :(得分:1)

您可以使用thisthis

之类的内容

但是,要修复代码,您需要更改焦点。您需要将其附加到文本字段,而不是将MouseListener附加到pnlGrid。这样做的原因是鼠标事件就像雨滴一样,任何带有附件MouseListener的组件都会像伞一样,阻止MouseEvents出现在视觉下方的组件上

要将MouseEvent从一个组件上下文转换为另一个组件上下文,您可以使用SwingUtilities.convertMouseEventSwingUtilities.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?

答案 1 :(得分:0)

好吧,在上面的例子中,每个单独的编辑小部件都是吃老鼠的。

普通的Java表只是在一个面板中显示该表,然后当它被单击时,它会在那时创建一个控件来处理编辑。因此,它不是一大堆编辑控件。结果证明效率很低。

所以,解决方案是“不做你正在做的事情”#34;。或者使用已经尝试过的分层窗格。

附录:

问题是你有一系列头等组件,每个组件都有自己的&#34; little&#34;矩形,而不是更大的单一组成部分。这就是您遇到的问题。 Swing正在处理所有这些标签和个别事物(因为它们是)。与容器相比,他们没有任何全球背景可以轻松报告。您必须根据转换为&#34;全球&#34;的本地坐标进行推断。在较大的小组内协调。