如何使用swing类Java绘制网格并在单击和拖动时检测鼠标位置

如何使用swing类Java绘制网格并在单击和拖动时检测鼠标位置,java,swing,grid,jpanel,mouseover,Java,Swing,Grid,Jpanel,Mouseover,我正在尝试使用Swing类创建一个网格UI(5*5)。我尝试了一个嵌套循环,并向jFrame动态添加了一个jPanel。我还尝试在用户点击并落在每个jPanel上时改变其背景颜色。 但是在我的代码中,每个单元格之间都有巨大的间隙,我无法让拖动事件正常工作 public class clsCanvasPanel extends JPanel { private static final int intRows = 5; private static final int intCol

我正在尝试使用Swing类创建一个网格UI(5*5)。我尝试了一个嵌套循环,并向jFrame动态添加了一个jPanel。我还尝试在用户点击并落在每个jPanel上时改变其背景颜色。 但是在我的代码中,每个单元格之间都有巨大的间隙,我无法让拖动事件正常工作

public class clsCanvasPanel extends JPanel {
    private static final int intRows = 5;
    private static final int intCols = 5;
    private List<JPanel> jpllist = new ArrayList<JPanel>();

    public clsCanvasPanel() {                           
        /*
         * 
         * Add eventListener to individual JPanel within CanvasPanel
         *
         * 
         * TODO : 
         * 1) mousePressed --> update Temperature and HeatConstant of clsElement Class
         * 2) start a new thread and  
         * 3) call clsElement.run() method
         * 
         * 
         * Right Now : it updates the colours of the JPanel
         * */
          MouseListener mouseListener = new MouseAdapter() {
             @Override
             public void mousePressed(MouseEvent e) {
                JPanel panel = (JPanel) e.getSource();

                Component[] components = panel.getComponents();
                for (Component component : components) {
                   component.setVisible(!component.isVisible());
                   component.setBackground(new Color(255,255,0));
                }
                panel.revalidate();
                panel.repaint();
             }
          };

          //TODO : refactoring
          GridLayout gdlyPlates = new GridLayout();
          gdlyPlates.setColumns(intCols);
          gdlyPlates.setRows(intRows);
          gdlyPlates.setHgap(0);
          gdlyPlates.setVgap(0);
          setLayout(gdlyPlates);

          //TODO : refactoring
          for (int row = 0; row < intRows; row++) {
              for (int col = 0; col < intCols; col++) {
                 JPanel panel = new JPanel(new GridBagLayout());
                 panel.setOpaque(false);
                 JPanel jl = new JPanel();
                 jl.setVisible(true);
                 panel.add(jl);
                 panel.addMouseListener(mouseListener);
                 jpllist.add(panel);
                 add(panel);
              }
           }
    }
}
public类clsCanvasPanel扩展了JPanel{
私有静态最终int intRows=5;
私有静态final int intCols=5;
private List jpllist=new ArrayList();
公共clsCanvasPanel(){
/*
* 
*将eventListener添加到CanvasPanel中的单个JPanel
*
* 
*待办事项:
*1)鼠标按下-->更新clsElement类的温度和热常数
*2)启动一个新线程并
*3)调用clsElement.run()方法
* 
* 
*现在:它更新了JPanel的颜色
* */
MouseListener MouseListener=新的MouseAdapter(){
@凌驾
公共无效鼠标按下(MouseEvent e){
JPanel面板=(JPanel)e.getSource();
Component[]components=panel.getComponents();
用于(组件:组件){
setVisible(!component.isVisible());
组件。立根(新颜色(255255,0));
}
panel.revalidate();
panel.repaint();
}
};
//TODO:重构
GridLayout gdlyPlates=新的GridLayout();
gdlyPlates.setColumns(intCols);
gdlyPlates.设置行(插入);
gdlyPlates.setHgap(0);
gdlyPlates.setVgap(0);
设置布局(gdlyPlates);
//TODO:重构
for(int行=0;行
所以现在我尝试创建一个面板,在上面画网格,然后检测鼠标在网格上的位置,进一步改变每个单元格的颜色


有没有人能给我一些建议,告诉我如何在JPanel上实现这个网格,以及如何更改所选单元格的颜色。

根据您想要实现的目标,有很多方法可以实现这个功能

第一个示例仅使用2D Graphics API渲染单元格,并使用
MouseMotionListener
监视高亮显示的单元格

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestGrid01 {

    public static void main(String[] args) {
        new TestGrid01();
    }

    public TestGrid01() {
        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 int columnCount = 5;
        private int rowCount = 5;
        private List<Rectangle> cells;
        private Point selectedCell;

        public TestPane() {
            cells = new ArrayList<>(columnCount * rowCount);
            MouseAdapter mouseHandler;
            mouseHandler = new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    Point point = e.getPoint();

                    int width = getWidth();
                    int height = getHeight();

                    int cellWidth = width / columnCount;
                    int cellHeight = height / rowCount;

                    selectedCell = null;
                    if (e.getX() >= xOffset && e.getY() >= yOffset) {

                        int column = (e.getX() - xOffset) / cellWidth;
                        int row = (e.getY() - yOffset) / cellHeight;

                        if (column >= 0 && row >= 0 && column < columnCount && row < rowCount) {

                            selectedCell = new Point(column, row);

                        }

                    }
                    repaint();

                }
            };
            addMouseMotionListener(mouseHandler);
        }

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

        @Override
        public void invalidate() {
            cells.clear();
            selectedCell = null;
            super.invalidate();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            int width = getWidth();
            int height = getHeight();

            int cellWidth = width / columnCount;
            int cellHeight = height / rowCount;

            int xOffset = (width - (columnCount * cellWidth)) / 2;
            int yOffset = (height - (rowCount * cellHeight)) / 2;

            if (cells.isEmpty()) {
                for (int row = 0; row < rowCount; row++) {
                    for (int col = 0; col < columnCount; col++) {
                        Rectangle cell = new Rectangle(
                                xOffset + (col * cellWidth),
                                yOffset + (row * cellHeight),
                                cellWidth,
                                cellHeight);
                        cells.add(cell);
                    }
                }
            }

            if (selectedCell != null) {

                int index = selectedCell.x + (selectedCell.y * columnCount);
                Rectangle cell = cells.get(index);
                g2d.setColor(Color.BLUE);
                g2d.fill(cell);

            }

            g2d.setColor(Color.GRAY);
            for (Rectangle cell : cells) {
                g2d.draw(cell);
            }

            g2d.dispose();
        }
    }
}


在MuleMeRever方法中的Mouististor示例中,您可能需要考虑XOffice/YOffice,以获得更平滑的小区识别。

int column = (x - xOffset) / cellWidth;
int row = (y - yOffset) / cellHeight;

我不喜欢渲染边框,因为在网格内,如果有超过示例的边框,则会复制一些边框。我认为这个解决方案更好:

private int width;
private int height;

// ...

for (int row = 0; row <= this.height; row++) {
    for (int col = 0; col <= this.width; col++) {
        gbc.gridx = col;
        gbc.gridy = row;

        CellPane cellPane = new CellPane();
        Border border = new MatteBorder(1, 1, (row == this.height ? 1 : 0), (col == this.width ? 1 : 0), Color.GRAY);

        cellPane.setBorder(border);
        this.add(cellPane, gbc);
    }
}
private int-width;
私人内部高度;
// ...

对于(int row=0;row你好,我意识到这是一篇非常古老的帖子。嘿@MadProgrammer,你的代码太棒了!我抓起它来修补我的作业,但我有点为难,这正是我需要的,但我需要使窗口1080x760,有1700个单元格,每个单元格都是20x20。现在我已经重新划分了窗口,并制作了1700个单元格,我遇到的问题是,当我尝试将单元格大小调整为20x20时,鼠标侦听器会发疯,无法正常工作……我尝试过更改cellWidth和cellHeight变量……但效果不太好……有什么想法吗?@Twhite1195哪个版本,第一个还是第二个?@MadProgrammer first,第二个非常有效。。。直到我调整了cells@Twhite1195你的
columnCount
rowCount
值是多少?@MadProgrammer
columnCount
是50,而
rowCount
是36。你能回答一下为什么你的解决方案能解决这个问题吗?
private int width;
private int height;

// ...

for (int row = 0; row <= this.height; row++) {
    for (int col = 0; col <= this.width; col++) {
        gbc.gridx = col;
        gbc.gridy = row;

        CellPane cellPane = new CellPane();
        Border border = new MatteBorder(1, 1, (row == this.height ? 1 : 0), (col == this.width ? 1 : 0), Color.GRAY);

        cellPane.setBorder(border);
        this.add(cellPane, gbc);
    }
}