不准确的网格单元坐标

gv8xihay  于 2021-07-13  发布在  Java
关注(0)|答案(2)|浏览(402)

使用swing和awt我创建了一个网格。用户可以单击网格中的任何空单元格,将其标记为红色单元格。网格由20 x 20个单元组成,每个单元32个像素。
当用户单击一个单元格时,我会得到鼠标单击的x和y坐标,并执行以下计算以找出哪个单元格是选定的:

int mouseX = e.getX();
int mouseY = e.getY();

int row = mouseY / Model.NODE_SIZE;
int col = mouseX / Model.NODE_SIZE;

问题是,当我在单元格边缘(右边框或下边框)附近单击时,行和列会变得不准确(错误),从而导致标记下一个单元格(右侧单元格或底部单元格),而不是标记我正在单击的正确单元格。
越接近网格的右/下边界,精度就越差。
我是这样画网格的:

public class MainPanel extends JPanel {

// reference to the model
private Model model;

public MainPanel() {

    setPreferredSize(new Dimension(660, 660));

    // retrieve the model
    model = Controller.getController().getModel();

    // draw 
    repaint();

    // listen to mouse clicks
    addMouseListener(new MouseAdapter() {

        @Override
        public void mouseClicked(MouseEvent e) {

            int mouseX = e.getX();
            int mouseY = e.getY();

            System.out.println("mouseX: " + mouseX + " mouseY: " + mouseY);

            // get the row and column clicked
            int row = mouseY / Model.NODE_SIZE;
            int col = mouseX / Model.NODE_SIZE;

            if(row > Model.BOARD_SIZE - 1 || col > Model.BOARD_SIZE - 1) { // avoid out of bounds
                return;
            }

            System.out.println("row: " + row + " col: " + col);

            Controller.getController().getModel().setTarget(col, row);

            repaint();
        }
    });
}

/**
 * Custom painting codes on this JPanel 
 * Called by repaint()
 */
@Override
public void paintComponent(Graphics g) { 
    super.paintComponent(g);    // fills background
    setBackground(Color.WHITE); // sets background color

    // draw the tiles
    Node[][] nodes = model.getBoard();

    for(int i = 0; i < Model.BOARD_SIZE; i++) {
        for(int j = 0; j < Model.BOARD_SIZE; j++) {
            if(nodes[i][j].getNodeType() == NodeType.OBSTACLE) {
                g.setColor(Color.BLACK);
                g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
            }
            else if(nodes[i][j].getNodeType() == NodeType.SOURCE) {
                g.setColor(Color.GREEN);
                g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
            }
            else if(nodes[i][j].getNodeType() == NodeType.TARGET) {
                g.setColor(Color.RED);
                g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
            }
            else {
                g.setColor(Color.BLACK);
                g.drawRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
            }
        }
    }
}

}
链接到runnable:
https://www.dropbox.com/s/bqoimipp7i1f39s/gridexample.jar?dl=0

zed5wv10

zed5wv101#

你的油漆代码是错的,基本上。。。

g.drawRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);

是将每个单元格的大小增加一个已绘制行/单元格的系数,例如。。。

绿线是用 g.drawRect(0, 0, BOARD_SIZE * NODE_SIZE, BOARD_SIZE * NODE_SIZE); ,它应该是网格的可见区域,但您正在绘制超出它的区域。
相反,如果我用。。。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
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;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new MainPanel());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class MainPanel extends JPanel {

        public static final int NODE_SIZE = 32;
        public static final int BOARD_SIZE = 8;

        private int row, col = -1;

        public MainPanel() {

            // listen to mouse clicks
            addMouseListener(new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {

                    int mouseX = e.getX();
                    int mouseY = e.getY();

                    System.out.println("mouseX: " + mouseX + " mouseY: " + mouseY);

                    // get the row and column clicked
                    int row = mouseY / NODE_SIZE;
                    int col = mouseX / NODE_SIZE;

                    if (row > BOARD_SIZE - 1 || col > BOARD_SIZE - 1) { // avoid out of bounds
                        return;
                    }

                    System.out.println("row: " + row + " col: " + col);

                    repaint();
                }
            });

            addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    int mouseX = e.getX();
                    int mouseY = e.getY();
                    row = mouseY / NODE_SIZE;
                    col = mouseX / NODE_SIZE;
                    repaint();
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(BOARD_SIZE * NODE_SIZE, BOARD_SIZE * NODE_SIZE);
        }

        /**
         * Custom painting codes on this JPanel Called by repaint()
         */
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);    // fills background
            setBackground(Color.WHITE); // sets background color

            g.setColor(Color.GREEN);

            for (int i = 0; i < BOARD_SIZE; i++) {
                for (int j = 0; j < BOARD_SIZE; j++) {
                    if (row == j && col == i) {
                        g.setColor(Color.RED);
                        g.fillRect(NODE_SIZE * i, NODE_SIZE * j, NODE_SIZE, NODE_SIZE);
                    }
                    g.setColor(Color.BLACK);
                    g.drawRect(NODE_SIZE * i, NODE_SIZE * j, NODE_SIZE, NODE_SIZE);
                }
            }
        }
    }
}

它变得更加准确了。。

另一个想法是 Rectangle 要定义网格的每个单元格,可以使用 Rectangle#contains 测试鼠标是否在任何给定的单元格范围内…作为一个想法

kulphzqa

kulphzqa2#

查看此代码:

g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);

结合本规范:

int row = mouseY / Model.NODE_SIZE;
int col = mouseX / Model.NODE_SIZE;

是可疑的,你在屏幕上画的矩形大小为 i + Model.NODE_SIZE * i -所以屏幕上矩形的大小在前面的每个矩形中偏移1。这个偏移会使你所选矩形的潜在“检测”变得更糟,你点击屏幕右下角的距离越远。
我怀疑如果你把密码改成

g.fillRect(Model.NODE_SIZE * i, Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);

它将按预期工作。

相关问题