Swing - UI 更改不受影响

问题描述 投票:0回答:1

我正在使用创建 GridPanel 时指定的宽度和高度在用户界面上绘制网格草图。出于代表性目的,我将网格从 30、30 开始,到 x - 60、y - 60 结束。根据网格尺寸,使用scaleX 和scaleY 实现动态收缩和增长。

下图显示了单元格对象的内部结构。

Cell object

GenerateMaze 是一种递归回溯算法,用于生成完美的迷宫。 (当然不完整,但我仍然应该能够看到结果。)

public class GridPanel extends JPanel {
    private class Cell {
        private int y, x;
        private int[] south;
        private int[] north;
        private int[] west;
        private int[] east;

        private Cell(int y, int x) {
            this.y = y;
            this.x = x;

            this.south = new int[4];
            this.north = new int[4];
            this.west = new int[4];
            this.east = new int[4];
        }
    }

    private int w, h;
    private final int scaleX, scaleY;
    private final int Vx, Vy;
    private final Cell[][] grid;
    private boolean[][] discovered;

    public GridPanel(int w, int h) {
        setLayout(new GridLayout(1, 1));

        this.w = w;
        this.h = h;

        scaleX = (int) (w / Math.sqrt(w));
        scaleY = (int) (h / Math.sqrt(h));

        Vx = w / scaleX;
        Vy = w / scaleY;

        discovered = new boolean[Vy][Vx];

        grid = new Cell[Vy][Vx];
        init(grid);
    }

    private void init(Cell[][] grid) {
        for (int j = 0; j < grid.length; j++) {
            for (int i = 0; i < grid[0].length; i++) {
                grid[j][i] = new Cell(j, i);
            }
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        setDoubleBuffered(true);
        g.setColor(Color.CYAN);

        for (int y = 30, j = 0; y < h - 60; y += scaleY, j++) {
            for (int x = 30, i = 0; x < w - 60; x += scaleX, i++) {
                Cell cell = grid[j][i];

                cell.east = new int[]{x, y, x, y + scaleY};
                cell.west = new int[]{x + scaleX, y, x + scaleX, y + scaleY};
                cell.north = new int[]{x, y, x + scaleX, y};
                cell.south = new int[]{x, y + scaleY, x + scaleX, y + scaleY};

                g.drawLine(cell.east[0], cell.east[1], cell.east[2], cell.east[3]);
                g.drawLine(cell.west[0], cell.west[1], cell.west[2], cell.west[3]);
                g.drawLine(cell.south[0], cell.south[1], cell.south[2], cell.south[3]);
                g.drawLine(cell.north[0], cell.north[1], cell.north[2], cell.north[3]);
            }
        }

        generateMaze(g, 0, 0);
    }

    private void generateMaze(Graphics g, int y, int x) {
        discovered[y][x] = true;

        while (true) {
            Cell current = grid[y][x];

            if (validUp(y) && !discovered[y - 1][x]) {
                removeWall(g, current.north);
                generateMaze(g, y - 1, x);
            }
            if (validDown(y) && !discovered[y + 1][x]) {
                removeWall(g, current.south);
                generateMaze(g, y + 1, x);
            }
            if (validRight(x) && !discovered[y][x + 1]) {
                removeWall(g, current.east);
                generateMaze(g, y, x + 1);
            }
            if (validLeft(x) && !discovered[y][x - 1]) {
                removeWall(g, current.west);
                generateMaze(g, y, x - 1);
            }

            // All neighbors have been visited, break the loop
            break;
        }
    }


    private boolean validLeft(int x) {
        if (x - 1 < 0) return false;
        return true;
    }

    private boolean validRight(int x) {
        if (x + 1 < grid[0].length) return true;
        return false;
    }

    private void removeWall(Graphics g, int[] coordinate) {
        SwingUtilities.invokeLater(() -> {
            g.setColor(Color.BLACK);
            g.drawLine(coordinate[0], coordinate[1], coordinate[2], coordinate[3]);
        });
    }

    private boolean validDown(int y) {
        if (y + 1 < grid.length) return true;
        return false;
    }

    private boolean validUp(int y) {
        if (y - 1 < 0) return false;
        return true;
    }
}

° 应用框架:

public class Maze extends JFrame {
    private int w, h;

    public Maze(int w, int h) throws HeadlessException {
        super("Perfect Maze");
        setResizable(false);
        setBackground(Color.BLACK);

        this.w = w;
        this.h = h;

        add(new GridPanel(w, h));

        setSize(w, h);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }
}

° 跑步者:

public class Main {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new Maze(800, 800);
        });
    }
}

鉴于用户界面出现并且应用程序成功关闭,我相信removeWall函数是问题的原因。

当我尝试在方法末尾添加方法:repaint() 时,它不起作用。

java swing user-interface maze custom-painting
1个回答
0
投票

简介

我重新编写了您的绘图代码并提出了以下 GUI。这是你的迷宫网格,没有移除墙壁。

如果您通过单击右上角的框展开 GUI,网格大小将会调整。很难看到,因为 Stack Overflow 会缩放图像。

说明

当我创建 Swing GUI 时,我使用 模型-视图-控制器 (MVC) 模式。这种模式使我能够将我的关注点分开,一次专注于 Java 应用程序的一小部分。

Swing 模型由一个或多个普通 Java getter/setter 类组成。

Swing 视图由一个

JFrame
和任意多个
JPanels
JDialogs
组成。

每个 Action 或 Listener 都是一个 Swing 控制器。通常没有一个控制器可以“统治所有”。

型号

我重写了你的 Cell 类。您不需要坐标,因为网格中的单元格位置提供了坐标。

public class Cell {
    
    private boolean north, south, east, west;
    
    public Cell() {
        this.north = true;
        this.south = true;
        this.east = true;
        this.west = true;
    }

    public boolean isNorth() {
        return north;
    }

    public void setNorth(boolean north) {
        this.north = north;
    }

    public boolean isSouth() {
        return south;
    }

    public void setSouth(boolean south) {
        this.south = south;
    }

    public boolean isEast() {
        return east;
    }

    public void setEast(boolean east) {
        this.east = east;
    }

    public boolean isWest() {
        return west;
    }

    public void setWest(boolean west) {
        this.west = west;
    }
    
}

创建迷宫的代码将通过将适当的

boolean
设置为
false
来移除单元格的墙壁; Swing 视图代码将绘制网格的状态。时期。没有别的了。

这是

PerfectMazeModel
课程。

public class PerfectMazeModel {
    
    public final Cell[][] grid;
    
    public PerfectMazeModel() {
        this.grid = new Cell[40][40];
        for (int y = 0; y < grid.length; y++) {
            for (int x = 0; x < grid[y].length; x++) {
                grid[y][x] = new Cell();
            }
        }
    }

    public Cell[][] getGrid() {
        return grid;
    }
    
}

在这里我们创建网格。您不必将网格设为正方形。

查看

我使用

JFrame
并创建了一个绘图
JPanel
。绘图代码有点复杂。

public class DrawingPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    
    private final PerfectMazeModel model;
    
    public DrawingPanel(PerfectMazeModel model) {
        this.model = model;
        this.setPreferredSize(new Dimension(800, 800));
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        Cell[][] grid = model.getGrid();
        int margin = 20;
        int width = this.getWidth() - 2 * margin;
        int height = this.getHeight() - 2 * margin;
        int cellWidth = width / grid[0].length;
        int cellHeight = height / grid.length;
        int cellDimension = Math.min(cellWidth, cellHeight);
        
        int dx = margin;
        int dy = margin;
        for (int y = 0; y < grid.length; y++) {
            for (int x = 0; x < grid[y].length; x++) {
                Cell cell = grid[y][x];
                if (cell.isNorth()) {
                    g.drawLine(dx, dy, dx + cellDimension, dy);
                }
                if (cell.isWest()) {
                    g.drawLine(dx, dy, dx, dy + cellDimension);
                }
                if (cell.isSouth()) {
                    int cx = dx + cellDimension;
                    int cy = dy + cellDimension;
                    g.drawLine(dx, cy, cx, cy);
                }
                if (cell.isEast()) {
                    int cx = dx + cellDimension;
                    int cy = dy + cellDimension;
                    g.drawLine(cx, dy, cx, cy);
                }
                dx += cellDimension;
            }
            dx = margin;
            dy += cellDimension;
        }
    }
}

我们根据当前绘图的宽度和高度获取单元格尺寸

JPanel

x和y是网格单元的逻辑坐标。 dx 和 dy 是网格单元的左上角。 cx和cy是网格单元的右上和左下点。我们根据布尔标志画线。

单元格/网格模型并不完美,因为一个单元格的东线与相邻单元格的西线是同一条线。对于单元格的南北线也是如此。

控制器

由于我只是显示模型和绘图代码,因此没有控制器。我已经为您添加了删除行的代码。

代码

这是完整的可运行代码。我创建了额外的类内部类,这样我就可以将此代码作为一个块发布。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class PerfectMaze implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new PerfectMaze());
    }
    
    private final DrawingPanel drawingPanel;
    
    private final PerfectMazeModel model;
    
    public PerfectMaze() {
        this.model = new PerfectMazeModel();
        this.drawingPanel = new DrawingPanel(model);
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Perfect Maze");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(drawingPanel, BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    public void drawingPanelRepaint() {
        this.drawingPanel.repaint();
    }
    
    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        private final PerfectMazeModel model;
        
        public DrawingPanel(PerfectMazeModel model) {
            this.model = model;
            this.setPreferredSize(new Dimension(800, 800));
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            
            Cell[][] grid = model.getGrid();
            int margin = 20;
            int width = this.getWidth() - 2 * margin;
            int height = this.getHeight() - 2 * margin;
            int cellWidth = width / grid[0].length;
            int cellHeight = height / grid.length;
            int cellDimension = Math.min(cellWidth, cellHeight);
            
            int dx = margin;
            int dy = margin;
            for (int y = 0; y < grid.length; y++) {
                for (int x = 0; x < grid[y].length; x++) {
                    Cell cell = grid[y][x];
                    if (cell.isNorth()) {
                        g.drawLine(dx, dy, dx + cellDimension, dy);
                    }
                    if (cell.isWest()) {
                        g.drawLine(dx, dy, dx, dy + cellDimension);
                    }
                    if (cell.isSouth()) {
                        int cx = dx + cellDimension;
                        int cy = dy + cellDimension;
                        g.drawLine(dx, cy, cx, cy);
                    }
                    if (cell.isEast()) {
                        int cx = dx + cellDimension;
                        int cy = dy + cellDimension;
                        g.drawLine(cx, dy, cx, cy);
                    }
                    dx += cellDimension;
                }
                dx = margin;
                dy += cellDimension;
            }
        }
    }
    
    public class PerfectMazeModel {
        
        public final Cell[][] grid;
        
        public PerfectMazeModel() {
            this.grid = new Cell[40][40];
            for (int y = 0; y < grid.length; y++) {
                for (int x = 0; x < grid[y].length; x++) {
                    grid[y][x] = new Cell();
                }
            }
        }

        public Cell[][] getGrid() {
            return grid;
        }
        
    }
    
    public class Cell {
        
        private boolean north, south, east, west;
        
        public Cell() {
            this.north = true;
            this.south = true;
            this.east = true;
            this.west = true;
        }

        public boolean isNorth() {
            return north;
        }

        public void setNorth(boolean north) {
            this.north = north;
        }

        public boolean isSouth() {
            return south;
        }

        public void setSouth(boolean south) {
            this.south = south;
        }

        public boolean isEast() {
            return east;
        }

        public void setEast(boolean east) {
            this.east = east;
        }

        public boolean isWest() {
            return west;
        }

        public void setWest(boolean west) {
            this.west = west;
        }
        
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.