0

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);
}
Andrei Sh
  • 113
  • 1
  • 11
  • Learn how to do multi-threading in a `Swing` application: https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html – PM 77-1 May 07 '19 at 22:11
  • 1
    `static` is really dangerous in this context, try and avoid it. You should be able to pass a `SwingWorker` to a `ExecutorService`, so the program the boils down how to use a `SwingWorker` to update the UI, which has been asked and solved numerous times – MadProgrammer May 07 '19 at 22:11
  • 1
    [`SwingWorker` and `ExecutorService` example](https://stackoverflow.com/questions/27031148/make-images-fetched-from-server-display-in-real-time/27031322#27031322) – MadProgrammer May 07 '19 at 22:15
  • Thanks. I'll try to inspect that example. – Andrei Sh May 07 '19 at 22:42

0 Answers0