Search code examples
javaswingjbuttonjprogressbarinvokelater

How to bind a JProgressBarr progress to a JButton preventing it from freezing?


that's the code i'm using, for the MAIN class:

public class Main {

public static void main(String[] args) throws Exception  {

MAINFRAME.GUI();
  }
}

now that's about the mainframe class that is called from the main class:

public class MAINFRAME extends JFrame {

final static JProgressBar PROGBAR = new JProgressBar(0, 100);
final static JButton BUTTON = new JButton("START");
final static JFrame FRM = new JFrame();

private static ZipFile zipFile;
static BufferedInputStream bis;
static java.io.BufferedOutputStream bout;
static java.io.BufferedInputStream in;


     public static void GUI() throws Exception {

     //Some frame code

     frm.add(PROGBAR);
     frm.add(BUTTON);

     //Some more frame code

     BUTTON.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
            try {
              MAINFRAME.DOWNLOAD();
                }
            catch (Exception e1) {
               e1.printStackTrace();
                }
             }
       });

     //Some more code

     public static final void DOWNLOAD() throws Exception {
       try {
        URL url=new URL(URLHERE);
        HttpURLConnection connection =
             (HttpURLConnection) url.openConnection();
         int filesize = connection.getContentLength();
         float totalDataRead=0;
             in = new java.io.BufferedInputStream(connection.getInputStream());
             java.io.FileOutputStream fos = new java.io.FileOutputStream(FILE);
             bout = new BufferedOutputStream(fos,1024);
             byte[] data = new byte[1024];
             int i=0;
             while((i=in.read(data,0,1024))>=0)
             {
             totalDataRead=totalDataRead+i;
             bout.write(data,0,i);
             float Percent=(totalDataRead*100)/filesize;
             PROGBAR.setValue((int)Percent);
             }

             bout.close();
             in.close();
      }
  }
  catch(Exception e)
  {
       System.out.println("Error");         
  }
}

Everything works fine, downloading unzipping etc etc but the bar that should show the progress keeps frozen till the operation finishes, and goes on 100% when the process finishes, now, i red something about InvokeLater but i'm really struggling to understand how to apply it on here and how it works, thank you in advance


Solution

  • To avoid the UI blocking, you have to put long-running tasks into a separated thread.

    BUTTON.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    try {
                        new Thread(new Runnable() {
    
                            @Override
                            public void run() {
                                MAINFRAME.DOWNLOAD();
                            }
                        }).start();
                    } catch (Exception e1) {
                        e1.printStackTrace();
                    }
                }
            });
    

    You can also use a SwingWorker. Here is an answered question about it.