Java GUI 更改'tile'的位置



我正在制作一个带有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()的主类

当用户左键单击网格时,他们会在该位置创建一个WALL。如果它已经是一堵墙,它就会变为空白。我希望用户能够通过点击开始和结束磁贴,然后拖动到他们想要停止的位置来移动它,这是我遇到的问题。任何帮助我都将不胜感激,因为我已经被难住了一段时间了。

您需要在MouseListener接口中实现mousePressedmouseReleased处理程序,在MouseMotionListener中实现mouseDragged处理程序。

首先,让MouseLsntr扩展MouseAdapter类,默认情况下实现MouseListenerMouseMotionListener

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瓷砖将在拖动时跟随鼠标。

最新更新