有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我正在尝试使用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);
              }
           }
    }
}

所以现在我试着创建一个面板,在上面画网格,然后检测鼠标在网格上的位置,进一步改变每个单元格的颜色

有人能给我一些建议,如何在JPanel上实现这个网格,并改变所选单元格的颜色吗


共 (3) 个答案

  1. # 1 楼答案

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

    int column = (x - xOffset) / cellWidth;
    int row = (y - yOffset) / cellHeight;
    
  2. # 2 楼答案

    有很多方法可以让它发挥作用,这取决于你想要实现什么

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

    enter image description here

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

    本例确实使用窗口调整网格大小,但将单元格设置为固定大小只是一个很小的改变

    查看2D Graphics了解更多详细信息

    使用组件示例更新

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

    每个单元格都定义有固定的宽度和高度,不随主窗口调整大小

    enter image description here

    在本例中,每个单元格面板都有自己的鼠标侦听器。重新编写代码,使主面板有一个鼠标侦听器,并自行管理工作负载,并不太困难

    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);
            }
        }
    }
    
  3. # 3 楼答案

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

    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。。。一些细胞的内边缘会相互接触,并在某些地方形成厚厚的网格。很高兴在截图上看到 thick grid