如何在 Java Swing 中的 while 循环迭代后等待 [英] How to wait after an iteration of a while loop in Java Swing

查看:23
本文介绍了如何在 Java Swing 中的 while 循环迭代后等待的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

有趣的 bfs(): MutableList?{Grid.resetNodes()val 队列:队列<节点>= 链表()queue.add(Grid.start!!)Grid.start!!.state = State.IN_QUEUE而 (queue.isNotEmpty()) {val 当前 = queue.poll()//打印(当前)current.state = State.CLOSEif (current == Grid.end!!) 中断Grid.getNodeNeighbours(current).forEach { node ->if (node.state == State.OPEN) {node.parent = 当前queue.add(节点)node.state = State.IN_QUEUE}}GridPanel.repaint()}返回 getPath()}

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

解决方案

Swing 是一个单线程库.所有绘制任务都由

I'm programming a path finder visualizer with Kotlin and Java Swing and I have this Breadth-First Search function:

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()
}

After each iteration of the while loop I want to redraw the Grid and wait a few seconds to make the algorithm view a little slower. I tried using Swing Timers, but I couldn't get it to work. I can't use 'Thread.sleep()' too because of Java Swing.

解决方案

Swing is a single Thread library. All painting tasks are executed by the EDT.
Running long processes (such BFS) on the EDT keeps it busy, so it does not do update the gui (gui becomes unresponsive, freezes).
Run the long process on a different thread, but remember that all Swing gui updates needs to be done by the EDT.
The different thread is where you can apply a delay for slowing down the process for better visualization.
A good tool to perform such tasks is a SwingWorker.
The following is a single-file mre (copy-paste the entire code to AlgoVisualitation.java and run) demonstrating the basic structure:

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

public class AlgoVisualitation {

    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) {

        AlgoVisualitation av = new AlgoVisualitation();
        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);
    }
}

(Run it online)


这篇关于如何在 Java Swing 中的 while 循环迭代后等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆