二维网格不适合路径可视化工具的 JFrame

2D grid is not fitting in JFrame for pathing visualizer

我正在尝试创建一个二维网格,其节点大小取决于框架 height/width 的大小,但是每当我 运行 程序时,底行和右列都会被剪掉离开。这是我的执行代码:

public class PathfindingVisualizer {
    public static void main(String[] args) {
        Grid grid = new Grid(10,10, new Dimension(1000, 1000));

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new GridFrame(grid);
            }
        });
    }
}

这是网格 class:

package gui;

import javax.swing.*;
import java.awt.*;
import java.util.Arrays;

public class Grid extends JPanel {
    private final int rows, cols;
    private final Node[][] grid;
    private Node start, end;
    private final Dimension size;
    private int nodeSize;

    public Grid(int rows, int cols, Dimension size) {
        this.rows = rows;
        this.cols = cols;
        this.grid = new Node[cols][rows];
        this.size = size;
        this.nodeSize = getWidth() / cols;
        initializeGrid();
    }

    public void initializeGrid() {
        // populate grid as a 2D array of Nodes
        for (int col=0; col<cols; col++) {
            for (int row=0; row<rows; row++) {
                grid[col][row] = new Node(col, row);
            }
        }

        // create neighbors for all the Nodes
        for (int col=0; col<cols; col++) {
            for (int row=0; row<rows; row++) {
                setNeighbors(col, row);
            }
        }

        // create start and end points for pathfinding
        start = grid[0][0];
        end = grid[cols-1][rows-1];
    }

    private void setNeighbors(int col, int row) {
        int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

        for (int[] direction : directions) {
            int neighborCol = direction[0] + col;
            int neighborRow = direction[1] + row;

            if (neighborCol >= 0 && neighborCol < cols &&
                neighborRow >= 0 && neighborRow < rows) {
                if (Arrays.equals(direction, new int[]{1, 0})) {
                    grid[col][row].setDown(grid[neighborCol][neighborRow]);
                }
                if (Arrays.equals(direction, new int[]{-1, 0})) {
                    grid[col][row].setUp(grid[neighborCol][neighborRow]);
                }
                if (Arrays.equals(direction, new int[]{0, 1})) {
                    grid[col][row].setRight(grid[neighborCol][neighborRow]);
                }
                if (Arrays.equals(direction, new int[]{0, -1})) {
                    grid[col][row].setLeft(grid[neighborCol][neighborRow]);
                }
            }
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLACK);
        for (int col=0; col<cols; col++) {
            for (int row=0; row<rows; row++) {
                g.drawRect(col*nodeSize, row*nodeSize, nodeSize, nodeSize);
            }
        }
    }

    public int getRows() {
        return rows;
    }

    public int getCols() {
        return cols;
    }

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

    @Override
    public Dimension getSize() {
        return size;
    }

    public int getHeight(){
        return (int) size.getHeight();
    }

    public int getWidth(){
        return (int) size.getWidth();
    }
}

这是 GridFrame class:

package gui;

import javax.swing.*;
import java.awt.*;

public class GridFrame {
    public GridFrame(Grid grid) {
        JFrame frame = new JFrame("Pathfinding Visualizer");
        frame.setPreferredSize(grid.getSize());
        frame.setContentPane(grid);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

我也一直在搞乱具有绘图功能的实现 w/in 节点 class 但到目前为止还没有任何运气。

这里的目标是制作一个路径可视化工具。这是我的第一个 Java 项目,所以任何帮助都是有帮助的!

编辑: 这也是节点 class:

package gui;

public class Node {
    private final int row, col;
    private Node up, down, left, right;
    private boolean start, end, wall, visited;

    public Node(int col, int row) {
        this.col = col;
        this.row = row;
    }

    public int getRow() {
        return row;
    }

    public int getCol() {
        return col;
    }

    public Node getUp() {
        return up;
    }

    public void setUp(Node up) {
        this.up = up;
    }

    public Node getDown() {
        return down;
    }

    public void setDown(Node down) {
        this.down = down;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    public boolean isStart() {
        return start;
    }

    public void setStart(boolean start) {
        this.start = start;
    }

    public boolean isEnd() {
        return end;
    }

    public void setEnd(boolean end) {
        this.end = end;
    }

    public boolean isWall() {
        return wall;
    }

    public void setWall(boolean wall) {
        this.wall = wall;
    }

    public boolean isVisited() {
        return visited;
    }

    public void setVisited(boolean visited) {
        this.visited = visited;
    }
}

让我们从……开始吧

Grid grid = new Grid(10,10, new Dimension(1000, 1000));

public Grid(int rows, int cols, Dimension size) {
        this.rows = rows;
        this.cols = cols;
        this.grid = new Node[cols][rows];
        this.size = size;
        this.nodeSize = getWidth() / cols;
        initializeGrid();
}

像这样将 Dimension 传递到构造函数中是个坏主意,除了您完全忽略高度这一事实之外,您最终可能会截断整数(getWidth() / cols 会很简单截取小数值并且不会应用任何类型的舍入,这可能会给您带来错误的结果)

接下来你做...

this.nodeSize = getWidth() / cols;

在正常情况下,getWidth 此时会 return 0,除非你...

@Override
public Dimension getSize() {
    return size;
}

public int getHeight() {
    return (int) size.getHeight();
}

public int getWidth() {
    return (int) size.getWidth();
}

这是非常值得怀疑的(而且根本不推荐)。还记得我讲过“整数截断”吗?这可能意味着组件的大小是 bigger/small 那么整个网格的实际面积。也不建议覆盖 getSize,因为您会弄乱布局管理系统,这可能会产生无穷无尽的长期问题。

最后,你的问题的关键是...

frame.setPreferredSize(grid.getSize());

你似乎没有意识到的是,可视内容大小是frame size - window decorations,这使得你的程序的可视区域<1000x1000

那么,答案是什么?改为传递单个单元格的大小...

private int cellSize;

public Grid(int rows, int cols, int cellSize) {
    this.rows = rows;
    this.cols = cols;
    this.grid = new String[cols][rows];
    this.cellSize = cellSize;
    initializeGrid();
}

并覆盖 getPreferredSize(而不是 getSize)...

@Override
public Dimension getPreferredSize() {
    return new Dimension(cellSize * cols, cellSize * rows);
}

显然 paintComponent

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.setColor(Color.BLACK);
    for (int col = 0; col < cols; col++) {
        for (int row = 0; row < rows; row++) {
            g.drawRect(col * cellSize, row * cellSize, cellSize, cellSize);
        }
    }
}

并摆脱

 frame.setPreferredSize(grid.getSize());

可运行示例...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new Grid(10, 10, 100));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class Grid extends JPanel {
        private final int rows, cols;
        private final String[][] grid;
        private int cellSize;

        public Grid(int rows, int cols, int cellSize) {
            this.rows = rows;
            this.cols = cols;
            this.grid = new String[cols][rows];
            this.cellSize = cellSize;
            initializeGrid();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(cellSize * cols, cellSize * rows);
        }

        public void initializeGrid() {
            // populate grid as a 2D array of Nodes
            for (int col = 0; col < cols; col++) {
                for (int row = 0; row < rows; row++) {
                    grid[col][row] = col + "x" + row;
                }
            }

            // create neighbors for all the Nodes
            for (int col = 0; col < cols; col++) {
                for (int row = 0; row < rows; row++) {
                    setNeighbors(col, row);
                }
            }

            // create start and end points for pathfinding
            //start = grid[0][0];
            //end = grid[cols - 1][rows - 1];
        }

        private void setNeighbors(int col, int row) {
            //int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
            //
            //for (int[] direction : directions) {
            //    int neighborCol = direction[0] + col;
            //    int neighborRow = direction[1] + row;
            //
            //    if (neighborCol >= 0 && neighborCol < cols
            //            && neighborRow >= 0 && neighborRow < rows) {
            //        if (Arrays.equals(direction, new int[]{1, 0})) {
            //            grid[col][row].setDown(grid[neighborCol][neighborRow]);
            //        }
            //        if (Arrays.equals(direction, new int[]{-1, 0})) {
            //            grid[col][row].setUp(grid[neighborCol][neighborRow]);
            //        }
            //        if (Arrays.equals(direction, new int[]{0, 1})) {
            //            grid[col][row].setRight(grid[neighborCol][neighborRow]);
            //        }
            //        if (Arrays.equals(direction, new int[]{0, -1})) {
            //            grid[col][row].setLeft(grid[neighborCol][neighborRow]);
            //        }
            //    }
            //}
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.BLACK);
            for (int col = 0; col < cols; col++) {
                for (int row = 0; row < rows; row++) {
                    g.drawRect(col * cellSize, row * cellSize, cellSize, cellSize);
                }
            }
        }

        public int getRows() {
            return rows;
        }

        public int getCols() {
            return cols;
        }

        //public Node[][] getGrid() {
        //    return grid;
        //}
    }
}