2

I have a JButton(swing) in the JPanel, where if it is pressed I am performing a task on the for loop over the list in its EDT thread. While doing so I need to update the JProgressBar.

Problem is, when I am pressing the JButton the task is performed in Event Dispatch Thread (EDT). So I can't update the JProgressBar which is triggered either in main or UI thread.

Right now the source code is not available at me as I completely changed it and tried to use Eclipse SWT for JProgressBar when that Swing JButton is triggered, it becomes messy.

Now I got invalid thread access error, as the Display object runs in separate UI thread. At a time, only either a Swing JPanel or Eclipse SWT Shell gets displayed.

I am triggering JPanel using JOptionPane.

Dinesh Ravi
  • 1,209
  • 1
  • 17
  • 35
  • You need to do your long running job and updating the progress bar value in a separate Thread. Most of the time `SwingWorker` is a good way to do that. You can find out how to use it in these examples: https://stackoverflow.com/questions/782265/how-do-i-use-swingworker-in-java and http://www.javacreed.com/swing-worker-example/ – STaefi Jan 08 '18 at 07:22
  • 1
    Mixing SWT and Swing is very difficult, stick to all Swing or all SWT. – greg-449 Jan 08 '18 at 07:56
  • 1
    As I don't know all the business of your application, maybe switching to SWT is necessary or not. But only for such an update on `JProgressBar` there is no need to switch to SWT. Check my answer. – STaefi Jan 08 '18 at 08:35

2 Answers2

3

Asynchronously handling JProgressBar progress using SwingWorker in detailed using two Swing JButton btnStart and btnStop.

enter image description here

and here we go for the source code-

package com.practice;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class ProgressExample {

    private static JFrame frame;
    private static JButton btnStart;
    private static JButton btnStop;
    private static JProgressBar progress;
    private static Integer currValue;
    private static boolean swingWorkerHelper;
    private static SwingWorker<Integer, Void> swingWorker;

    public static void main(String[] args) {
        // Scheduling Swing app for the event dispatch thread(EDT) Asynchronously
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                runSwingAsynchronousApp();
            }
        });
    }

    private static void runSwingAsynchronousApp() {
        currValue = new Integer(0);

        btnStart = new JButton("Start");
        btnStop = new JButton("Stop");

        progress = new JProgressBar();
        progress.setMinimum(0);
        progress.setMaximum(100);
        progress.setStringPainted(true);

        btnStart.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {

                if (btnStart.getText().equals("Pause")) {
                    // interrupting swingWorker method doInBackground() implicitly safely.
                    swingWorkerHelper = false;
                    btnStart.setText("Resume");
                } else {
                    if (btnStart.getText().equals("Start") || btnStart.getText().equals("Resume"))
                        btnStart.setText("Pause");

                    showProgress();
                }
            }
        });

        btnStop.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                // checking swingWorker Object is initialized or not
                if (swingWorker != null) {
                    // checking is swingWorker doing process in background or not
                    if (swingWorker.getState() == SwingWorker.StateValue.STARTED) {
                        btnStart.setText("Start");
                        // interrupting swingWorker method doInBackground() explicitly
                        swingWorker.cancel(true);
                        currValue = new Integer(0);
                    }
                }
            }
        });

        frame = new JFrame();
        frame.setTitle("Asynchronously trigger JProgressBar");
        frame.getContentPane().setLayout(new GridLayout(3, 2));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(400, 250, 400, 300);

        frame.getContentPane().add(btnStart);
        frame.getContentPane().add(btnStop);
        frame.getContentPane().add(progress);

        frame.setVisible(true);
    }

    private static void showProgress() {
        swingWorker = new SwingWorker<Integer, Void>() {
            @Override
            protected Integer doInBackground() throws Exception {

                if (!swingWorkerHelper)
                    swingWorkerHelper = true;

                while (currValue < progress.getMaximum() && swingWorkerHelper) {
                    try {
                        progress.setValue(++currValue);

                        if (isCancelled())
                            return currValue;

                        Thread.sleep(70);
                    } catch (InterruptedException iex) {
                        swingWorkerHelper = false;
                        System.out.println("Stop Button interrupted SwingWorker process...");
                    }
                }
                return currValue;
            }

            @Override
            public void done() {
                System.out.printf("Progress ends with value %s " + 
                (isCancelled() ? "with" : "without") + " interruption.\n", currValue);
                if (currValue >= progress.getMaximum()) {
                    btnStart.setText("Start");
                    currValue = new Integer(0);
                }
            }
        };
        swingWorker.execute();
    }

}

Hope this would help you.

ArifMustafa
  • 4,617
  • 5
  • 40
  • 48
2

You need to do your long running job and updating the progress bar value in a separate Thread from EDT. Most of the time SwingWorker is a good way to do that. So in your ActionListener of that button you should separate the long running thread from the EDT. You can do it with bare Thread but Workers and specially SwingWorker is designed for such cases:

package graphics;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class GraphicDev extends JFrame{

    private static final long serialVersionUID = 679207429168581441L;
    //
    private static final int FRAME_WIDTH = 300;
    private static final int FRAME_HEIGHT = 100;

    private int percent;
    private JProgressBar progress;

    public GraphicDev() {
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(dim.width/2-FRAME_WIDTH/2, dim.height/2-FRAME_HEIGHT/2, FRAME_WIDTH, FRAME_HEIGHT);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //
        setLayout(new FlowLayout());
        //
        progress = new JProgressBar(0, 100);
        progress.setStringPainted(true);
        //
        JButton actButton = new JButton("Start!");
        actButton.addActionListener(new ActionListener() {          
            @Override
            public void actionPerformed(ActionEvent e) {
                new SwingWorker<Void, Void>() {
                    @Override
                    protected Void doInBackground() throws Exception {
                        for (long i = 0; i < 10000000000000L; i++) {
                            System.out.println(i);
                            if(i%200000 == 0){
                                progress.setValue(percent++);
                            }
                            if(percent >= 100){
                                break;
                            }
                        }
                        return null;
                    }

                    @Override
                    protected void done() {
                        JOptionPane.showMessageDialog(GraphicDev.this, "Done!");
                    }

                }.execute();    
            }
        });
        //
        add(actButton);
        add(progress);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                GraphicDev g = new GraphicDev();
                g.setVisible(true);
            }
        });
    }
}

Hope this would be helpful.

STaefi
  • 4,297
  • 1
  • 25
  • 43