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 中的 JLabel 中设置行距/高度?