I am trying to create a program to solve quadratic equation and calculate the solving time. I have JButton that when i clicked it, the calculation will begin. My SwingWorker is for counting time, it will update time every 1 second. Because the calculation is fast, I call Thread.sleep() in JButton actionPerformed so i can see SwingWorker counting time, but when I call Thread.sleep(3000) in EDT thread, SwingWorker doesn't work but wait after the equation solving is finished to print out running time = 3s. How can i fix this so SwingWorker will update time every 1 second instead of printing out just 3s.
//SwingWorker for counting time
public class Worker extends SwingWorker<Integer, Long> {
private JLabel label;
public Worker(JLabel label) {
this.label = label;
}
@Override
protected Integer doInBackground() throws Exception {
long i = System.currentTimeMillis();
Timer SimpleTimer = new Timer(10, new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
publish(System.currentTimeMillis() - i);
}
});
SimpleTimer.start();
return 1;
}
protected void process(List<Long> chunks) {
for(long i : chunks) {
label.setText("" + i);
}
}
}
//Solving quadratic function in JButton actionPerformed
private void solveActionPerformed(java.awt.event.ActionEvent evt) {
int a, b, c;
double x1, x2;
int i = 0;
try {
a = Integer.parseInt(inputA.getText());
b = Integer.parseInt(inputB.getText());
c = Integer.parseInt(inputC.getText());
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Re-enter.");
return;
}
Worker worker = new Worker(clock);
worker.execute();
try {
Thread.sleep(3000);
} catch (Exception e) {
}
double delta = b * b - 4 * a * c;
if(delta < 0) {
result.setText(".");
} else if(delta == 0) {
result.setText("x1 = x2 = " + -b / 2 * a);
} else {
x1 = (-b + Math.sqrt(delta)) / (2 * a);
x2 = (-b - Math.sqrt(delta)) / (2 * a);
result.setText("<html>x1 = " + x1 + "<br>x2 = " + x2 + "</html>");
}
}
I have found a solution now, i put the timer and the calculation code in a same thread class:
public class NewThread implements Runnable {
private JLabel label, result;
private int a, b, c;
public NewThread(JLabel label, int a, int b, int c, JLabel result) {
this.label = label;
this.a = a;
this.b = b;
this.c = c;
this.result = result;
}
@Override
public void run() {
double x1, x2;
long i = System.currentTimeMillis();
Timer timer = new Timer(10, new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
label.setText("Thoi gian tinh toan: " + (Math.round(System.currentTimeMillis() - i) / 1000) + " giay");
}
});
timer.start();
try {
Thread.sleep(3000);
} catch (Exception e) {
}
double delta = b * b - 4 * a * c;
if(delta < 0) {
result.setText("Phuong trinh vo nghiem.");
} else if(delta == 0) {
result.setText("Phuong trinh co nghiem kep x1 = x2 = " + -b / 2 * a);
} else {
x1 = (-b + Math.sqrt(delta)) / (2 * a);
x2 = (-b - Math.sqrt(delta)) / (2 * a);
result.setText("<html>Phuong co 2 nghiem.<br>x1 = " + x1 + "<br>x2 = " + x2 + "</html>");
}
timer.stop();
}
My SwingWorker is for counting time, it will update time every 1 second.
If the only responsibility of this worker is to update a label with the elapsed time, then a Swing Timer is a better candidate to do it. Let the SwingWorker doInBackground()
implementation do the heavy calculation and finally the done()
implementation may just stop the timer and display the final results.
Do not call Thread.sleep()
in the EDT because it will freeze the entire GUI event processing and you'll probably see just the final result without the intended periodic updates.
Adding just a simple snippet to start with:
public void startCalculation() {
Timer timer = new Timer(1000, new ActionListener() {
AtomicInteger elapsedSeconds = new AtomicInteger();
@Override
public void actionPerformed(ActionEvent evt) {
label.setText(String.format("Elapsed time: %d seconds", elapsedSeconds.incrementAndGet()));
}
});
SwingWorker<Integer, Void> worker = new SwingWorker<Integer, Void>() {
@Override
protected Integer doInBackground() throws Exception {
// do heavy stuff
Thread.sleep(3000); // it is safe to "sleep" here because it's not executed in the EDT
return 1;
}
@Override
protected void done() {
timer.stop();
// update the GUI with the results here if it's required
}
};
timer.start();
worker.execute();
}