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

我正在尝试使用Swing类创建一个网格UI(5 * 5)。 我尝试了一个嵌套循环,并动态地将jPanel添加到jFrame。 我还尝试在用户点击并删除时更改每个jPanel的背景颜色。 但是使用我的代码,每个单元格之间存在巨大差距,我无法使拖动事件起作用。

public class clsCanvasPanel extends JPanel { private static final int intRows = 5; private static final int intCols = 5; private List jpllist = new ArrayList(); 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); } } } } 

所以现在我尝试创建一个面板并在其上绘制网格,然后检测网格上的鼠标位置,进一步更改每个单元格的颜色。

有人可以给我一些关于如何在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 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(); } } } 

此示例使用窗口调整网格大小,但是使单元格固定大小将是一个微不足道的更改。

查看2D图形了解更多详情

使用组件示例更新

此示例使用一系列JPanel来表示每个单元格。

每个单元格都定义为固定的宽度和高度,并且不会随主窗口resize。

在此处输入图像描述

在此示例中,每个单元面板都有自己的鼠标侦听器。 重新编码它不会太困难,因此主面板只有一个鼠标监听器,而是自己管理工作负载。

 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 static void main(String[] args) { new 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 { public TestPane() { setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); for (int row = 0; row < 5; row++) { for (int col = 0; col < 5; col++) { gbc.gridx = col; gbc.gridy = row; CellPane cellPane = new CellPane(); Border border = null; if (row < 4) { if (col < 4) { border = new MatteBorder(1, 1, 0, 0, Color.GRAY); } else { border = new MatteBorder(1, 1, 0, 1, Color.GRAY); } } else { if (col < 4) { border = new MatteBorder(1, 1, 1, 0, Color.GRAY); } else { border = new MatteBorder(1, 1, 1, 1, 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.BLUE); } @Override public void mouseExited(MouseEvent e) { setBackground(defaultBackground); } }); } @Override public Dimension getPreferredSize() { return new Dimension(50, 50); } } } 

我不喜欢渲染边界,因为如果有更多的例子,在网格内部有些是重复的。 我认为这个解决方案更好:

 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); } } 

编辑:

我的解决方案更好,因为如果原始代码将是5x5单元格,但更多,例如10x10 ......某些单元格的内边缘将会接触并创建一些粗网格。 很高兴看到截图粗网格

在mouseMoved方法的MouseListener示例中,您可能需要考虑xOffset / yOffset,以获得更平滑的单元格识别。

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