Search code examples
javaswingswtjprogressbar

How to asynchronous trigger JProgressBar?


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.


Solution

  • 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.