I am using Java function to download file from internet.
public void getLatestRelease()
{
try
{
// Function called
long startTime = System.currentTimeMillis();
// Open connection
System.out.println("Connecting...");
URL url = new URL(latestReleaseUrl);
url.openConnection();
// Download routine
InputStream reader = url.openStream();
FileOutputStream writer = new FileOutputStream("release.zip");
byte[] buffer = new byte[153600];
int totalBytesRead = 0;
int bytesRead = 0;
while ((bytesRead = reader.read(buffer)) > 0)
{
writer.write(buffer, 0, bytesRead);
buffer = new byte[153600];
totalBytesRead += bytesRead;
}
// Download finished
long endTime = System.currentTimeMillis();
// Output download information
System.out.println("Done.");
System.out.println((new Integer(totalBytesRead).toString()) + " bytes read.");
System.out.println("It took " + (new Long(endTime - startTime).toString()) + " milliseconds.");
// Close input and output streams
writer.close();
reader.close();
}
// Here I catch MalformedURLException and IOException :)
}
And I have JProgressBar
component in my JPanel
, which is supposed to visualize download progress:
private static void createProgressBar(JPanel panel)
{
JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setValue(0);
progressBar.setStringPainted(true);
panel.add(progressBar, BorderLayout.SOUTH);
}
I'd like to separate "back-end" functions from "front-end" views, presented to users, by analogy with MVC in web applications.
So, function getLatestRelease()
lies in the package framework
in class MyFramework
.
Everything, connected with Swing
interface generation, including event listeners, is in the package frontend
.
In the main Controller
class I create an instance of MyFramework
and an instance of ApplicationFrontend
, which is the main class of frontend
package.
The questions is how to update progressBar
value, depending on download progress?
when you want to do MVC in swing, the SwingWorker
class comes to mind.
SwingWorker comes with a property called "progress", that you can listen to using a PropertyChangeListener
.
Progress events can be fired from the swingworker using its setProgress(int 0-100)
method. So here it is for loading the file in the background with a notion of progress (note that you will need to have an idea of the size of the file to be able to compute a progress percentage).
Showing the progress can be done using two options : a JProgressBar
for complete control, or a ProgressMonitor
to show an almost self-managed popup with a progress bar in it. See the tutorial to see the differences.
As they say, if you go for a ProgressMonitor
and your background task is reading from an InputStream
, you can use the ProgressMonitorInputStream
class to do the reading and displaying progress without bothering with calling setProgress or listening to the "progress" property.
If you want to do it manually, create your SwingWorker loading task that calls setProgress as it goes, instanciate a ProgressMonitor (or a JProgressBar) as needed, register a PropertyChangeListener on your SwingWorker that checks for "progress" changes and updates the monitor/bar accordingly.
Note: It is important to go through a PropertyChangeListener because it decouples the model (the task) from the view (the swing progress component) and abide by the EDT usage rules.