java - 在 swing 中绘制时显示图形

标签 java arrays swing paintcomponent maze

我在 swing 中为一个类(class)创建了一个迷宫生成器,它运行得很好。唯一的问题是,我想显示实时创建的迷宫,但我设置所有内容的方式,它仅在所有计算完成后更新。我在代码中使用paintComponent 和repaint。我如何让它立即显示 JFrame 并绘制线条,而不是执行算法并在最后显示所有内容?

相关代码如下:

 public void generateMaze() {
        Stack<Box> stack = new Stack<>();
        int totalCells = Finals.numCol * Finals.numRow, visitedCells = 1;
        Box currentCell = boxes[0][0];
        Box nextCell;
        stack.add(currentCell);

        while (visitedCells < totalCells) {
            nextCell = checkNeighbors(currentCell.xCoord, currentCell.yCoord);
            if (nextCell != null) {
                knockWalls(currentCell, nextCell);
                stack.add(currentCell);
                currentCell = nextCell;
                visitedCells++;
            } else {
                currentCell = stack.pop();
            }
        }
        repaint();
    }

这是我的paintComponent方法重写

public void paintComponent(Graphics g) {
        for(int x = 0; x < Finals.numRow; x++) {
            for(int y = 0; y < Finals.numCol; y++) {
                if(boxes[y][x].top != null)
                    boxes[y][x].top.paint(g);
                if(boxes[y][x].bottom != null)
                    boxes[y][x].bottom.paint(g);
                if(boxes[y][x].left != null)
                    boxes[y][x].left.paint(g);
                if(boxes[y][x].right != null)
                    boxes[y][x].right.paint(g);
            }
        }
    }

knockWalls 方法将某些墙壁设置为 null,这会导致它们不会在 PaintComponent 方法中绘制。我对这方面还很陌生,所以如果某些代码质量不是很高,我深表歉意!

谢谢大家。

最佳答案

正如 MadProgrammer 已经在评论中指出的那样,您几乎肯定会阻塞事件调度线程。该线程负责重新绘制 GUI,并负责处理交互事件(例如鼠标单击和按钮按下)。

所以大概,您通过单击按钮开始计算,大致如下:

// The actionPerformed method of the button that
// starts the maze solving computation
@Override
void actionPerformed(ActionEvent e)
{
    generateMaze();
}

这意味着事件调度线程将忙于执行generateMaze(),并且无法执行重绘。

最简单的解决方案是将其更改为类似

// The actionPerformed method of the button that
// starts the maze solving computation
@Override
void actionPerformed(ActionEvent e)
{
    Thread thread = new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            generateMaze();  
        }
    });
    thread.start();
}

但是,必须小心:您可能从这个新创建的线程修改 Swing 组件。如果必须修改 Swing 组件,则必须使用 SwingUtilities.invokeLater(task) 将执行 Swing 组件实际修改的任务放回 EDT。此外,您必须确保不存在其他同步问题。例如,这些行

if(boxes[y][x].top != null)
    boxes[y][x].top.paint(g);

仍然(并且必须!)由事件调度线程执行。在这种情况下,您必须确保在 EDT 执行第一行之后没有其他线程可以将 boxes[y][x].top 设置为 null在执行第二行之前。如果这可能是您的情况的问题,您可能需要提供更多代码,例如显示 boxes[y][x] 修改位置和方式的代码。

关于java - 在 swing 中绘制时显示图形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22418175/

相关文章:

java - 在 Swing 应用程序中使用方法

javascript - 无法访问嵌套对象数组内的数据

php - 在 PHP 中从数组(Lat Long)获取数字

java - 在 JTable 中将数字格式化为货币?

java - 如何在没有窗口管理器的情况下在 SWT 中制作透明外壳?

java - 如何以编程方式在根 gradle.build 文件中创建子项目

java - 使用 jnlp 文件在小程序中无法进行延迟 jar 加载的原因可能是什么?

python - 在 Pandas 数据框上使用 str.contains

Java Swing - 添加图标或文本时 JLabel 宽度发生变化?

java - JScrollPane 隐藏 JTextPane