网格的单元格坐标不准确
Inaccurate grid's cells coordinates
我使用 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;
问题是,当我在单元格边缘(右边框或底边框)附近单击时,row 和 col 变得不准确(错误),导致标记下一个单元格(右边的单元格或右边的单元格)底部)而不是我点击的正确标记。
我越接近网格的 right/bottom 边界,精度就越差。
这是我绘制网格的方式:
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);
}
}
}
}
}
Link 到 runnable:
https://www.dropbox.com/s/bqoimipp7i1f39s/GridExample.jar?dl=0
看到这段代码:
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。此偏移量会使您选择的矩形的基础 "detection" 在您单击的屏幕右下角慢慢变得更糟。
我怀疑你是否将代码更改为
g.fillRect(Model.NODE_SIZE * i, Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
它将按预期工作。
你的绘画代码是错误的,基本上...
g.drawRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
将每个单元格的大小增加 row/cell 的一个因子,例如...
绿线是使用 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
来测试鼠标是否在任何给定的单元格边界内......因为一个想法
我使用 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;
问题是,当我在单元格边缘(右边框或底边框)附近单击时,row 和 col 变得不准确(错误),导致标记下一个单元格(右边的单元格或右边的单元格)底部)而不是我点击的正确标记。
我越接近网格的 right/bottom 边界,精度就越差。
这是我绘制网格的方式:
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);
}
}
}
}
}
Link 到 runnable:
https://www.dropbox.com/s/bqoimipp7i1f39s/GridExample.jar?dl=0
看到这段代码:
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。此偏移量会使您选择的矩形的基础 "detection" 在您单击的屏幕右下角慢慢变得更糟。
我怀疑你是否将代码更改为
g.fillRect(Model.NODE_SIZE * i, Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
它将按预期工作。
你的绘画代码是错误的,基本上...
g.drawRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
将每个单元格的大小增加 row/cell 的一个因子,例如...
绿线是使用 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
来测试鼠标是否在任何给定的单元格边界内......因为一个想法