我正在使用GUI开发A *寻路应用程序。我有:
-枚举TileType
START(Color.GREEN),
WALL(Color.BLACK),
BLANK(new Color(240, 240, 240)),
END(Color.RED);
-网格类
public class Grid extends JPanel {
private final Color lineColour = new Color(200, 200, 200);
private Color defaultColour;
private final int pixelsPerTile;
private final int rows;
private final int columns;
private TileType[][] tiles;
public Grid(int rows, int columns, int pixelsPerTile) {
this.pixelsPerTile = pixelsPerTile;
this.rows = rows;
this.columns = columns;
this.tiles = new TileType[rows][columns];
this.setPreferredSize(new Dimension(rows * pixelsPerTile, columns * pixelsPerTile));
setTile(rows / 2 - 5, columns / 2, TileType.START);
setTile(rows / 2 + 5, columns / 2, TileType.END);
}
public void resetBoard() {
for (int i = 0; i < tiles.length; i++) {
for (int j = 0; j < tiles[0].length; j++) {
if (getTile(i, j) != TileType.START && getTile(i, j) != TileType.END) {
tiles[i][j] = null;
}
}
}
}
public void removeTile(int x, int y) {
tiles[x][y] = TileType.BLANK;
}
public TileType getTile(int x, int y) {
return tiles[x][y];
}
public Point getTile(boolean start) {
for (int x = 0; x < tiles.length; x++) {
for (int y = 0; y < tiles[0].length; y++) {
if (tiles[x][y] == (start ? TileType.START : TileType.END)) {
return new Point(x, y);
}
}
}
return null;
}
public void setTile(int x, int y, TileType tile) {
if (getTile(x, y) != TileType.START && getTile(x, y) != TileType.END) {
tiles[x][y] = tile;
}
}
@Override
public void paint(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
for (int x = 0; x < columns; x++) {
for (int y = 0; y < columns; y++) {
if (getTile(x, y) != null) {
g.setColor(getTile(x, y).getColour());
g.fillRect(x * pixelsPerTile, y * pixelsPerTile, pixelsPerTile, pixelsPerTile);
}
}
}
// have the grid appear on top of blank tiles
g.setColor(lineColour);
for (int x = 0; x < columns; x++) {
for (int y = 0; y < rows; y++) {
g.drawLine(x * pixelsPerTile, 0, x * pixelsPerTile, getHeight());
g.drawLine(0, y * pixelsPerTile, getWidth(), y * pixelsPerTile);
}
}
}
public int getPixelsPerTile() {
return pixelsPerTile;
}
public int getRows() {
return rows;
}
public int getColumns() {
return columns;
}
}
-框架类
public class Frame extends JFrame {
private Grid grid;
public Frame() {
grid = new Grid(33, 33, 15); // odd so there is a definitive middle point
this.setAutoRequestFocus(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setTitle("A* Path finder");
this.setBounds(new Rectangle((grid.getRows()) * grid.getPixelsPerTile(),
(grid.getColumns() + 2) * grid.getPixelsPerTile()));
this.setResizable(true);
this.add(grid);
this.setVisible(true);
this.getContentPane().addMouseListener(new MouseLsntr()); // fixes alignment problems
ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(5);
se.scheduleAtFixedRate(new RedrawGrid(), 0L, 20L, TimeUnit.MILLISECONDS);
}
private class RedrawGrid implements Runnable {
@Override
public void run() {
grid.repaint();
}
}
private class MouseLsntr implements MouseListener {
@Override
public void mouseClicked(MouseEvent me) {
int x = me.getX() / grid.getPixelsPerTile();
int y = me.getY() / grid.getPixelsPerTile();
switch (me.getButton()) {
case MouseEvent.BUTTON1:
if (grid.getTile(x, y) != TileType.WALL) {
grid.setTile(x, y, TileType.WALL);
System.out.println(String.format("(%d, %d) (%d, %d) wall", x, y, x, y));
} else {
grid.removeTile(x, y);
System.out.println(String.format("(%d, %d) (%d, %d) blank", x, y, x, y));
}
break;
}
}
@Override
public void mousePressed(MouseEvent me) {}
@Override
public void mouseReleased(MouseEvent me) {}
@Override
public void mouseEntered(MouseEvent me) {}
@Override
public void mouseExited(MouseEvent me) {}
}
}
显然是一个主类,它调用Frame()
当用户在网格上单击鼠标左键时,他们将在该位置进行围墙。如果已经是墙壁,则变为空白。我希望用户能够通过单击它,然后将其拖动到他们想要停止的位置来移动“开始”和“结束”磁贴,但是我在这样做时遇到了麻烦。因为我已经为此困扰了一段时间,所以任何帮助将不胜感激。
最佳答案
您将需要在mousePressed
接口中实现mouseReleased
和MouseListener
处理程序,并在mouseDragged
中实现MouseMotionListener
处理程序。
首先,使您的MouseLsntr
扩展MouseAdapter
类,默认情况下实现MouseListener
和MouseMotionListener
。
private class MouseLsntr extends MouseAdapter {
private int dragStartX, dragStartY;
private boolean dragging;
@Override
public void mouseClicked(MouseEvent me) {
int x = me.getX() / grid.getPixelsPerTile();
int y = me.getY() / grid.getPixelsPerTile();
switch (me.getButton()) {
case MouseEvent.BUTTON1:
if (grid.getTile(x, y) != TileType.WALL) {
grid.setTile(x, y, TileType.WALL);
System.out.println(String.format("(%d, %d) (%d, %d) wall", x, y, x, y));
} else {
grid.removeTile(x, y);
System.out.println(String.format("(%d, %d) (%d, %d) blank", x, y, x, y));
}
break;
}
}
@Override
public void mousePressed(MouseEvent me) {
switch (me.getButton()) {
case MouseEvent.BUTTON1:
// Save the drag starting position.
this.dragStartX = me.getX() / grid.getPixelsPerTile();
this.dragStartY = me.getY() / grid.getPixelsPerTile();
this.dragging = true;
break;
}
}
@Override
public void mouseReleased(MouseEvent me) {
switch (me.getButton()) {
case MouseEvent.BUTTON1:
if (this.dragging) {
moveTile(me);
}
this.dragging = false;
break;
}
}
@Override
public void mouseExited(MouseEvent me) {
this.dragging = false;
}
@Override
public void mouseDragged(MouseEvent me) {
if (this.dragging) {
moveTile(me);
}
}
private void moveTile(MouseEvent me) {
int dragEndX = me.getX() / grid.getPixelsPerTile();
int dragEndY = me.getY() / grid.getPixelsPerTile();
TileType dragStartType = grid.getTile(this.dragStartX, this.dragStartY);
TileType dragEndType = grid.getTile(dragEndX, dragEndY);
// If the starting tile was either START or END, move the tile to the destination.
if ((dragEndType == TileType.BLANK || dragEndType == null) &&
(dragStartType == TileType.START || dragStartType == TileType.END)) {
grid.removeTile(this.dragStartX, this.dragStartY);
grid.setTile(dragEndX, dragEndY, dragStartType);
// update the drag starting points
this.dragStartX = dragEndX;
this.dragStartY = dragEndY;
}
}
}
接下来,也将您的
MouseLsntr
实例也添加为MouseMotionListener
,以便在拖动时调用mouseDragged
处理程序。请注意,不应共享两个MouseLsntr
实例,因为成员字段应该共享。您应该像在Frame()
构造函数中那样进行操作。 MouseLsntr listener = new MouseLsntr();
this.getContentPane().addMouseListener(listener);
this.getContentPane().addMouseMotionListener(listener);
完成此操作后,TileType.START / TileType.END磁贴将在拖动时跟随鼠标。