Java Swing progress bar for download process - java

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.
Solution 1
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.
Solution 2
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.

Related

Eclipse "Widget is disposed" Error

Alright so I'm using Eclipse Oxygen here (I think that's important since it looks like this is an Eclipse-generated error). I've seen several other posts on this specific error, but none of them worked for me/weren't things I had already tried. So my goal is to have a while loop and have it get the db sound level every second and update a label.
Unfortunately, that didn't work like 5 times in a row. The first, the window didn't open, and I realized it was because the while loop was keeping the window from opening, so I put it into a thread. And then like 5 attempts to fix it later, I'm still getting a "Widget is disposed" error in my code. Here's the code for opening the window (that's the only code I've changed since I made the project):
public void open() throws InterruptedException, LineUnavailableException {
Display display = Display.getDefault();
shlAudioAdjuster = new Shell();
shlAudioAdjuster.setSize(450, 300);
shlAudioAdjuster.setText("Audio Adjuster");
Label lblCurrentDecibelLevel = new Label(shlAudioAdjuster, SWT.NONE);
lblCurrentDecibelLevel.setFont(SWTResourceManager.getFont("Muli", 14, SWT.NORMAL));
ProgressBar progressBar = new ProgressBar(shlAudioAdjuster, SWT.NONE);
progressBar.setSelection(30);
progressBar.setBounds(143, 168, 170, 17);
shlAudioAdjuster.open();
shlAudioAdjuster.layout();
while (!shlAudioAdjuster.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
AudioFormat audioFormat = getAudioFormat();
TargetDataLine targetDataLine;
try {
targetDataLine = (TargetDataLine) AudioSystem.getTargetDataLine(audioFormat);
targetDataLine.open();
targetDataLine.start();
byte [] buffer = new byte[2000];
while (true) {
int bytesRead = targetDataLine.read(buffer,0,buffer.length);
int max;
if (bytesRead >=0) {
max = (short) (buffer[0] + (buffer[1] << 8));
for (int p=2;p<bytesRead-1;p+=2) {
short thisValue = (short) (buffer[p] + (buffer[p+1] << 8));
if (thisValue>max) max=thisValue;
}
progressBar.setSelection((int)(20 * Math.log10(max)));
}
}
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
And the error confirms there is a problem with progressBar.setSelection((int)(20 * Math.log10(max)));. Here's the full error:
org.eclipse.swt.SWTException: Widget is disposed
at org.eclipse.swt.SWT.error(SWT.java:4533)
at org.eclipse.swt.SWT.error(SWT.java:4448)
at org.eclipse.swt.SWT.error(SWT.java:4419)
at org.eclipse.swt.widgets.Widget.error(Widget.java:482)
at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:354)
at org.eclipse.swt.widgets.ProgressBar.setSelection(ProgressBar.java:322)
at MainWindow.open(MainWindow.java:90)
at MainWindow.main(MainWindow.java:34)
P.S The last line of error saying 34 is the caller for that function, the first is the progress-bar-change line. Any ideas?
The Shell window is only displayed while the while (!shlAudioAdjuster.isDisposed()) loop is running. Once that loop has exited all the controls in the shell are disposed and cannot be used anymore. So you can't put your code after that while loop.
You will have to put the code playing the sound in a separate thread which you start when you open the shell. But you can't update the progress bar directly in a background thread, instead you need to use Display.asyncExec to run the progress bar update in the UI thread:
Display.getDefault().asyncExec(() -> progressBar.setSelection((int)(20 * Math.log10(max))));
You might also want to check if the progress bar has been disposed and stop the thread:
if (progressBar.isDisposed()) {
// TODO exit the thread
}

How do I Execute Java from Java?

I have this DownloadFile.java and downloads the file as it should:
import java.io.*;
import java.net.URL;
public class DownloadFile {
public static void main(String[] args) throws IOException {
String fileName = "setup.exe";
// The file that will be saved on your computer
URL link = new URL("http://onlinebackup.elgiganten.se/software/elgiganten/setup.exe");
// The file that you want to download
// Code to download
InputStream in = new BufferedInputStream(link.openStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int n = 0;
while (-1 != (n = in.read(buf))) {
out.write(buf, 0, n);
}
out.close();
in.close();
byte[] response = out.toByteArray();
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(response);
fos.close();
// End download code
System.out.println("Finished");
}
}
I want to execute this from a mouse event in Gui.java.
private void jLabel17MouseClicked(java.awt.event.MouseEvent evt){
}
How do I do this?
Your current method is a static method, which is fine, but all the data that it extracts is held tightly within the main method, preventing other classes from using it, but fortunately this can be corrected.
My suggestion:
re-write your DownloadFile code so that it is does not simply a static main method, but rather a method that can be called by other classes easily, and that returns the data from the file of interest. This way outside classes can call the method and then receive the data that the method extracted.
Give it a String parameter that will allow the calling code to pass in the URL address.
Give it a File parameter for the file that it should write data to.
Consider having it return data (a byte array?), if this data will be needed by the calling program.
Or if it does not need to return data, perhaps it could return boolean to indicate if the download was successful or not.
Make sure that your method throws all exceptions (such as IO and URL excptions) that it needs to throw.
Also, if this is to be called by a Swing GUI, be sure to call this type of code in a background thread, such as in a SwingWorker, so that this code does not tie up the Swing event thread, rendering your GUI frozen for a time.

Apache Wicket: File download that would not lock the page

I want to create a link that would initiate a file download which would be asynchronous to the page itself, i.e. I want the page not to be locked during the file download. Should I make it be initiated outside wicket? Or is there something inside wicket that would let me set up a resource stream which would bypass the page locks?
Things I tried:
DownloadLink - locks the page, as stated in its doc. This was my starting point.
ResourceLink - did not state the locking explicitly in the doc, so I tried this, but it also locked the page.
At this point I've investigated the code of both links a bit and noticed they both schedule the download via ResourceStreamRequestHandler. Expecting that his kind of behavior could be just handler-specific I've attempted to schedule a custom handler I've written:
private void sendFile(final File file) throws IOException {
IRequestHandler fileDownloadHandler = new IRequestHandler() {
#Override
public void respond(IRequestCycle requestCycle) {
WebResponse response = (WebResponse) requestCycle.getResponse();
OutputStream outStream = response.getOutputStream();
response.setContentType("audio/x-wav");
response.setContentLength((int)file.length());
String fileName = "Somethingsomething.wav";
// sets HTTP header
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
byte[] byteBuffer = new byte[1024];
DataInputStream in = null;
try {
in = new DataInputStream(new FileInputStream(file));
int length = 0;
// reads the file's bytes and writes them to the response stream
while ((in != null) && ((length = in.read(byteBuffer)) != -1))
{
outStream.write(byteBuffer,0,length);
}
in.close();
outStream.close();
} catch (IOException e) {
throw new PortalError("IOException trying to write the response", e);
}
}
#Override
public void detach(IRequestCycle requestCycle) {
}
};
getRequestCycle().scheduleRequestHandlerAfterCurrent(fileDownloadHandler);
}
This did not quite work either, so I've investigated further. I've noticed that unlike I expected, the "scheduled" request handlers would not get executed on a separate request, as I expected, but on the same one. I figured that it must be that the page gets locked for the first handler and then remains locked while the second one is executing as well. So I've attempted to force the download handler into a separate request (via an ajax behaviour):
public void startDownload(AjaxRequestTarget target) throws DownloadTargetNotFoundException{
target.appendJavaScript("setTimeout(\"window.location.href='" + getCallbackUrl() + "'\", 100);");
}
#Override
public void onRequest() {
sendFile(getFile());
logger.debug("Download initiated");
}
I've found this here and hoped it could potentially be what I've been looking for. However, unsurprisingly so, the page gets locked still (I would imagine because the behaviour still has to be retrieved from the page, for which the page lock has to be acquired).
I'm at a loss where I should be looking next, especially after all this time trying to get a simple download link working. I was considering creating another web filter one layer above wicket, which could be signaled from within wicket to create the download after the wicket filter is finished with its work (and hence the page lock is already released), but that seems a bit excessive for a task like this.
Any suggestions are welcome.
You have to download from a resource, see
http://wicketinaction.com/2012/11/uploading-files-to-wicket-iresource/ and read http://wicket.apache.org/guide/guide/resources.html

Remaiming file size counter

I'm trying to make a progress bar or something like that in my program that is sending files to a server. I've this
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(file.getName());
FileInputStream fis = new FileInputStream(file);
byte [] buffer = new byte[Server.BUFFER_SIZE];
Integer bytesRead = 0;
jj = size-bytesRead;
int i = 0;
while ((bytesRead = fis.read(buffer)) > 0) {
oos.writeObject(bytesRead);
jButton3.doClick();
oos.writeObject(Arrays.copyOf(buffer, buffer.length));
}
oos.close();
ois.close();
And this is Button3
temp = temp - 100;
jLabel3.setText(String.valueOf(temp));
temp is a size of chosen file and I'm subtracting 100 because it's the size of bytes in every step in the loop.
The problem is when I start sending file, Button3 is grayed till the end of sending doing nothing visible with label (like it is too slow to update the label on time) but at the end it's displaying a right data.
Why it can't periodically update the label? What should I do to fix that? Thanks for any advice.
You're probably doing the I/O on the Event Dispatch Thread, which is preventing the UI from processing its normal paint events. If you have a long-running operation, you shouldn't be doing it on the EDT (e.g. by doing it in an listener like ActionListener for a button click).
You need to do this work in a background thread and send updates to the UI. An easy way to do that is to use SwingWorker. Put the long-running code in doInBackground(). Call publish(byteCount) when you read some byteCount bytes. And then in process() update the progress bar.
Here's an example of SwingWorker that updates a JProgressBar: java update progressbar

load network-based images asynchronously in Java

I have to be able to load and draw X amount of images located on a network based drive.
I need help finding a way to load the images asynchronously.
java.net.URL Loc = new URL("http://auroragm.sourceforge.net/GameCover/GameCases/Mass-Effect.png");
JLabel lbl = new JLabel();
lbl.setIcon((anotherIcon = new ImageIcon(Loc)));
The above is one image which loads on the GUI thread and thus would freeze if 20 more were to be loaded. Any help would be appreciated
Load the images in separate thread. Please treat below code as pseudo-code:
final java.net.URL Loc = new URL("http://.../Mass-Effect.png");
Thread t = new Thread(new Runnable() {
public void run() {
Object content = Loc.getContent();
// content would be probably some Image class or byte[]
// or:
// InputStream in = Loc.openStream();
// read image from in
}
);
Short answer: you should load the images on another thread.
Swing does provide a nice set of classes & patterns for this:
http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html

Categories

Resources