I have a main frame. It has a button to start performing some tasks with an ExecutorService. Button also should show WaitDialog frame that shows tasks completion progress.
For now, after clicking on start button, it freezes and only after all are tasks completed, dialog frame with progress bar appears. Also, progress bar is set to 100%.
What have I done wrong?
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
//see https://stackoverflow.com/questions/16598000/executorservice-invokeall-progress-bar/16598690#16598690
public class AppGUI{
private JFrame frame;
public AppGUI() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setPreferredSize(new Dimension(1000, 800));
JButton button = new JButton("Let's do something");
panel.add(button);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//show dialog
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new WaitDialog(frame);
}
});
//tasks
MultiThreading.doSomething();
}
});
frame = new JFrame("I'm main frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new AppGUI();
}
});
}
}
class WaitDialog extends JDialog{
public static JProgressBar bar;
public WaitDialog(JFrame parent) {
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(300, 100));
JLabel label = new JLabel("We are doing something. Please wait...");
panel.add(label, BorderLayout.NORTH);
bar = new JProgressBar(0, 100);
bar.setStringPainted(true);
panel.add(bar, BorderLayout.CENTER);
JButton buttonCancel = new JButton("Cancel");
panel.add(buttonCancel, BorderLayout.CENTER);
buttonCancel.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//terminate tasks and close dialog
MultiThreading.shutdownAndAwaitTermination(MultiThreading.executor);
System.out.println("Tasks are canceled.");
dispose();
}
});
add(panel);
setUndecorated(true);
setModal(true); // impossible to close by program
//setAlwaysOnTop(true);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
//first
pack();
//second
setLocationRelativeTo(parent);
//third
setVisible(true);
}
}
class MultiThreading {
public static UpdateListener listener;
public static ExecutorService executor;
public static void doSomething() {
int numOfTasks = 50, completedTasks = 0;
List<Future<Integer>> results = new ArrayList<>();
executor = Executors.newFixedThreadPool(4);
listener = new UpdateListener() {
@Override
public void update(double percent) {
final double PERCENT = percent;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int v = (int) (100 * PERCENT);
WaitDialog.bar.setValue(v);
}
});
}
};
// Submit each of your tasks. Here I create them manually.
for (int i = 0; i < numOfTasks; ++i) {
final int I = i;
Callable<Integer> c = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
try {
Thread.sleep((long) 1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return new Integer(I);
}
};
results.add(executor.submit(c));
}
// Retrieve individual results and update progress bar.
for (Future<Integer> fr : results) {
try {
Integer i = fr.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
++completedTasks;
listener.update((double) completedTasks / numOfTasks);
}
}
public static void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(5, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
}
interface UpdateListener {
void update(double percent);
}