java - 如何在Java Swing中的while循环迭代后等待

Posted

技术标签:

【中文标题】java - 如何在Java Swing中的while循环迭代后等待【英文标题】:How to wait after an iteration of a while loop in Java Swing 【发布时间】:2021-10-24 04:46:52 【问题描述】:

我正在使用 Kotlin 和 Java Swing 编写路径查找器可视化工具,并且我有这个广度优先搜索功能:

fun bfs(): MutableList<Node>? 
    Grid.resetNodes()

    val queue: Queue<Node> = LinkedList()

    queue.add(Grid.start!!)
    Grid.start!!.state = State.IN_QUEUE

    while (queue.isNotEmpty()) 
        val current = queue.poll()
        //println(current)
        current.state = State.CLOSE

        if (current == Grid.end!!) break

        Grid.getNodeNeighbours(current).forEach  node ->
            if (node.state == State.OPEN) 
                node.parent = current
                queue.add(node)
                node.state = State.IN_QUEUE
            
        
        GridPanel.repaint()
    

    return getPath()

在 while 循环的每次迭代之后,我想重新绘制 Grid 并等待几秒钟以使算法视图变慢一点。 我尝试使用 Swing Timers,但我无法让它工作。由于 Java Swing,我也不能使用 'Thread.sleep()'。

【问题讨论】:

使用协程并插入延迟? 您不能只将算法插入到 Java Swing 应用程序中。您必须重写算法,以便一次处理的一个步骤发生在 javax.swing.Timer ActionListener 中。 Swing 是一个单线程库。所有绘画任务均由(EDT)执行。在 EDT 上运行长进程(例如 BFS)使其忙碌,因此它不会更新 gui(gui 冻结)。在不同的线程上运行长进程,最好使用SwingWorker,当您应用“等待”时也会出现这种情况。查看示例here 另一个example 请看***.com/help/someone-answers 【参考方案1】:

Swing 是一个单线程库。所有绘画任务均由EDT 执行。 在 EDT 上运行长进程(如 BFS)使其忙碌,因此它不会更新 gui(gui 变得无响应,冻结)。 在不同的线程上运行长进程,但请记住,所有Swing gui 更新都需要由 EDT 完成。 您可以在不同的线程中应用延迟以减慢进程以获得更好的可视化效果。 执行此类任务的好工具是SwingWorker。 以下是单个文件mre(将整个代码复制粘贴到AlgoVisualitation.java 并运行)演示基本结构:

import java.awt.*;
import java.util.List;
import java.util.Random;
import javax.swing.*;

public class SwingAlgoVisualization 

    private Cell[][] cells;
    private static final int SIZE = 3, GAP = 2;

    JPanel view() 

        JPanel gridPanel = new JPanel();
        gridPanel.setLayout(new GridLayout(SIZE, SIZE, GAP, GAP));
        gridPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP,GAP, GAP));
        cells = new Cell[SIZE][SIZE];

        for(int row=0; row <cells.length; row++) 
            for(int col=0; col<cells[row].length; col++) 
                Cell cell = new Cell();
                cells[row][col] = cell;
                gridPanel.add(cell.getComponent());
            
        
        return gridPanel;
    

     void solve()   
         //run long process on a SwingWorker
         new LongTask().execute();
     

    //use swing worker to perform long task off the EDT
    class LongTask extends SwingWorker<Void,int[]> 

        private static final long DELAY = 30;
        private final Random rand = new Random();

        @Override
        public Void doInBackground() 
            myLongComplexAlgo();
            return null;
        

        @Override
        //runs on EDT
        protected void process(List<int[]> results) 
            for(int[] result : results)
                cells[result[0]][result[1]].updateValue(result[2]);
            
        

        void myLongComplexAlgo()  //simulates long process that repeatedly updates gui

            while (true) //todo add stop mechanism
                //calculate(apply random value to random cell) and publish results
                int row = rand.nextInt(cells.length);
                int col = rand.nextInt(cells[0].length);
                int value = RandomValue.randomDigit();
                publish(new int[]row,col,value);

                try 
                    Thread.sleep(DELAY); //visualization delay
                 catch (InterruptedException ex)  ex.printStackTrace();
            
        
    

    public static void main(String[] args) 

        SwingAlgoVisualization av = new SwingAlgoVisualization();
        JFrame jFrame = new JFrame("Random Value Change");
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setLocationRelativeTo(null);
        jFrame.add(av.view());
        jFrame.pack();
        jFrame.setVisible(true);
        av.solve();
    


class Cell 

    private static int CELL_SIZE =100, BORDER = 1, FONT_SIZE = 20;

    private final JLabel label;
    Cell() 
        label = new JLabel();
        label.setFont(new Font("Calibri", Font.BOLD, FONT_SIZE));
        updateValue(RandomValue.randomDigit());
        label.setHorizontalAlignment(SwingConstants.CENTER);
        label.setBorder(BorderFactory.createLineBorder(Color.BLUE, BORDER));
        label.setPreferredSize(new Dimension(CELL_SIZE , CELL_SIZE));
        label.setOpaque(true);
    

    void updateValue(int value)
        label.setText(String.valueOf(value));
    

    JComponent getComponent()
        return label;
    


class RandomValue

    private static Random rand = new Random();

    public static int randomDigit()
        return rand.nextInt(10);
    

(运行它online)


【讨论】:

以上是关于java - 如何在Java Swing中的while循环迭代后等待的主要内容,如果未能解决你的问题,请参考以下文章

Java / Swing:JScrollPane中的JTextArea,如何防止自动滚动?

java如何衔接不同文件中的swing组件

如何在 Java Swing 中的 JLabel 中设置行距/高度?

Swing:关于Java界面编程的第一课,如何正确的处理界面中的线程

使用java中的swing将按钮放置在指定位置

如何使 JTable 中的列对 Swing Java 不可见