不准确的网格单元格坐标

时间:2016-03-28 07:11:55

标签: java swing awt

使用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

2 个答案:

答案 0 :(得分:4)

你的油漆代码错了,基本上......

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

将每个单元格的大小增加一个行/单元格的因子,例如......

Bad Screen

绿线是使用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

它变得更加准确..

Grid

另一个想法可能是使用Rectangle#contains来定义网格的每个单元格,这样你就可以使用Str.split_delim (Str.regexp " ") "this is my sentence";; - : bytes list = ["this"; "is"; "my"; "sentence"] 来测试鼠标是否在任何给定的单元格范围内......作为一个想法

答案 1 :(得分:3)

看到这段代码:

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

它将按预期工作。