1

Ok, I am creating a Java program that is to download mods for the game Minecraft. I have the following class that does all the downloading and that works fine. But I have an issue where the progress bar does not update whilst the mod is downloading (the whole program freezes whilst downloading)

After much research, other people seem to have the same issue and it can be resolved by using threads.

I just need to know if it is possible to do this using my existing code or do I have to completely re-write my this java class?

package com.anarcist.minemodloader;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.swing.JProgressBar;

public class modsDownloader {
    public static Boolean downloadMod(String mod, String saveLoc, JProgressBar progress){
        try {
            URL url = new URL(mod);
            //Set ProgressBar to 0%
            progress.setValue((int)0);
            //Open the Connection to the file
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            //Get filesize
            int filesize = connection.getContentLength();
            //Start reading at byte 0
            float totalDataRead = 0;

            BufferedInputStream in = new BufferedInputStream(connection.getInputStream());
            FileOutputStream fos = new FileOutputStream(saveLoc);
            BufferedOutputStream 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;
                progress.setValue((int)Percent);
            }
            bout.close();
            in.close();
        }catch(Exception e){
            javax.swing.JOptionPane.showConfirmDialog((java.awt.Component)
            null,e.getMessage(), "Error",
            javax.swing.JOptionPane.DEFAULT_OPTION);
        }
        return true;
    }
}

Additionally, this function/class is called using the following code:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    Object selectedObj = modsList.getSelectedValue();
    if (selectedObj instanceof modsListItem) {
        try {
            modsListItem selectedItem = (modsListItem) selectedObj;
            System.out.println(selectedItem.getValue());
            String fullName = selectedItem.getValue();
            String fileParts[] = fullName.split("/");
            String fileName = fileParts[fileParts.length - 1];
            String saveLoc = config.getModsFolder(true) + "/" + fileName;
            modsDownloader.downloadMod(selectedItem.getValue(), saveLoc, jProgressBar1);
        } catch (IOException ex) {
            Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
} 
Michael Smith
  • 625
  • 1
  • 8
  • 19
  • 2
    Well, you'll have to rewrite some of it, obviously. Read http://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html – JB Nizet Jun 27 '15 at 06:25
  • @JBNizet I have read this article, I was hoping I could call my `downloadMod` function from the `doInBackground` function. I have tried but not entirely sure on how to implement the parameters. – Michael Smith Jun 27 '15 at 06:29
  • That's the idea, axcept you may not use swing components (like the progress bar) from the doInBackground() method. If you want help with that, then post the code you tried. – JB Nizet Jun 27 '15 at 06:38
  • Throw it away and use `ProgressMonitorInputStream.` – user207421 Jun 27 '15 at 07:01

2 Answers2

1

This method call's yours and passes the parameters in a separated thread, but the return true statement is executed in the main thread, so, it may return true although your thread has not ended doing his work.

public static Boolean downloadModThread(String mod, String saveLoc, JProgressBar progress){
    new Thread(
        new Runnable(){
            public void run(){

                downloadMod(mod, saveLoc, progress);
            }
        }
    ).start();
    return true;

}
0

You can use Swing invokeAndWait() or invokeLater() invokeAndWait method in SwingUtilities concept like a FIFO logic the do a particular job and trigger something after it completes

You can use SwingWorker logic to perform a long running task and also update the UI periodically

Refer How do I use SwingWorker in Java?

Refer Stop/cancel SwingWorker thread?

Community
  • 1
  • 1
Dickens A S
  • 3,824
  • 2
  • 22
  • 45