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 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);
}
}
(Run it online)
