SwingWorker Kullanılanarak Yapılmış Progress Bar'a Sahip Bir Download Uygulaması
Bir Download uygulamasını, progress bar kullanarak -ki bu durumda SwingWorkerin yardımı lazım- nasıl hazırlandığını anlatan bir makale.
As we can see, the application consists of the following classes:
-
- HTTPDownloadUtil: encapsulates the core functionality of the application - download file from an HTTP URL. This class is implemented based on the tutorial Use HttpURLConnection to download file from an HTTP URL, but is modified to work with updating download progress while the file is being transferred.
- DownloadTask: executes the file download in a background thread rather in the Swing’s event dispatcher thread (EDT), so the GUI will not become unresponsive when the download is taking place.
- SwingFileDownloadHTTP: is the main application which displays the GUI that allows users to enter a download URL, choose a location to save the file, and start downloading.
- JFilePicker and FileTypeFilter: These components are used by the SwingFileDownloadHTTP class to show a file chooser. These classes are taken from the article File picker component in Swing.
Let’s see how these classes are implemented in details.
Code of the HTTPDownloadUtil class
package net.codejava.swing.download;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* A utility that downloads a file from a URL.
* @author www.codejava.net
*/
public class HTTPDownloadUtil {
private HttpURLConnection httpConn;
/**
* hold input stream of HttpURLConnection
*/
private InputStream inputStream;
private String fileName;
private int contentLength;
/**
* Downloads a file from a URL
*
* @param fileURL
* HTTP URL of the file to be downloaded
* @throws IOException
*/
public void downloadFile(String fileURL) throws IOException {
URL url = new URL(fileURL);
httpConn = (HttpURLConnection) url.openConnection();
int responseCode = httpConn.getResponseCode();
// always check HTTP response code first
if (responseCode == HttpURLConnection.HTTP_OK) {
String disposition = httpConn.getHeaderField("Content-Disposition");
String contentType = httpConn.getContentType();
contentLength = httpConn.getContentLength();
if (disposition != null) {
// extracts file name from header field
int index = disposition.indexOf("filename=");
if (index > 0) {
fileName = disposition.substring(index + 10,
disposition.length() - 1);
}
} else {
// extracts file name from URL
fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1,
fileURL.length());
}
// output for debugging purpose only
System.out.println("Content-Type = " + contentType);
System.out.println("Content-Disposition = " + disposition);
System.out.println("Content-Length = " + contentLength);
System.out.println("fileName = " + fileName);
// opens input stream from the HTTP connection
inputStream = httpConn.getInputStream();
} else {
throw new IOException(
"No file to download. Server replied HTTP code: "
+ responseCode);
}
}
public void disconnect() throws IOException {
inputStream.close();
httpConn.disconnect();
}
public String getFileName() {
return this.fileName;
}
public int getContentLength() {
return this.contentLength;
}
public InputStream getInputStream() {
return this.inputStream;
}
}
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* A utility that downloads a file from a URL.
* @author www.codejava.net
*/
public class HTTPDownloadUtil {
private HttpURLConnection httpConn;
/**
* hold input stream of HttpURLConnection
*/
private InputStream inputStream;
private String fileName;
private int contentLength;
/**
* Downloads a file from a URL
*
* @param fileURL
* HTTP URL of the file to be downloaded
* @throws IOException
*/
public void downloadFile(String fileURL) throws IOException {
URL url = new URL(fileURL);
httpConn = (HttpURLConnection) url.openConnection();
int responseCode = httpConn.getResponseCode();
// always check HTTP response code first
if (responseCode == HttpURLConnection.HTTP_OK) {
String disposition = httpConn.getHeaderField("Content-Disposition");
String contentType = httpConn.getContentType();
contentLength = httpConn.getContentLength();
if (disposition != null) {
// extracts file name from header field
int index = disposition.indexOf("filename=");
if (index > 0) {
fileName = disposition.substring(index + 10,
disposition.length() - 1);
}
} else {
// extracts file name from URL
fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1,
fileURL.length());
}
// output for debugging purpose only
System.out.println("Content-Type = " + contentType);
System.out.println("Content-Disposition = " + disposition);
System.out.println("Content-Length = " + contentLength);
System.out.println("fileName = " + fileName);
// opens input stream from the HTTP connection
inputStream = httpConn.getInputStream();
} else {
throw new IOException(
"No file to download. Server replied HTTP code: "
+ responseCode);
}
}
public void disconnect() throws IOException {
inputStream.close();
httpConn.disconnect();
}
public String getFileName() {
return this.fileName;
}
public int getContentLength() {
return this.contentLength;
}
public InputStream getInputStream() {
return this.inputStream;
}
}
This utility class does not actually download the file. It only makes a connection, parses HTTP headers to get file information, and opens the connection’s input stream which will be used by the DownloadTask class.
Code of the DownloadTask class
package net.codejava.swing.download;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
/**
* Execute file download in a background thread and update the progress.
* @author www.codejava.net
*
*/
public class DownloadTask extends SwingWorker<Void, Void> {
private static final int BUFFER_SIZE = 4096;
private String downloadURL;
private String saveDirectory;
private SwingFileDownloadHTTP gui;
public DownloadTask(SwingFileDownloadHTTP gui, String downloadURL, String saveDirectory) {
this.gui = gui;
this.downloadURL = downloadURL;
this.saveDirectory = saveDirectory;
}
/**
* Executed in background thread
*/
@Override
protected Void doInBackground() throws Exception {
try {
HTTPDownloadUtil util = new HTTPDownloadUtil();
util.downloadFile(downloadURL);
// set file information on the GUI
gui.setFileInfo(util.getFileName(), util.getContentLength());
String saveFilePath = saveDirectory + File.separator + util.getFileName();
InputStream inputStream = util.getInputStream();
// opens an output stream to save into file
FileOutputStream outputStream = new FileOutputStream(saveFilePath);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
long totalBytesRead = 0;
int percentCompleted = 0;
long fileSize = util.getContentLength();
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
percentCompleted = (int) (totalBytesRead * 100 / fileSize);
setProgress(percentCompleted);
}
outputStream.close();
util.disconnect();
} catch (IOException ex) {
JOptionPane.showMessageDialog(gui, "Error downloading file: " + ex.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
setProgress(0);
cancel(true);
}
return null;
}
/**
* Executed in Swing's event dispatching thread
*/
@Override
protected void done() {
if (!isCancelled()) {
JOptionPane.showMessageDialog(gui,
"File has been downloaded successfully!", "Message",
JOptionPane.INFORMATION_MESSAGE);
}
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
/**
* Execute file download in a background thread and update the progress.
* @author www.codejava.net
*
*/
public class DownloadTask extends SwingWorker<Void, Void> {
private static final int BUFFER_SIZE = 4096;
private String downloadURL;
private String saveDirectory;
private SwingFileDownloadHTTP gui;
public DownloadTask(SwingFileDownloadHTTP gui, String downloadURL, String saveDirectory) {
this.gui = gui;
this.downloadURL = downloadURL;
this.saveDirectory = saveDirectory;
}
/**
* Executed in background thread
*/
@Override
protected Void doInBackground() throws Exception {
try {
HTTPDownloadUtil util = new HTTPDownloadUtil();
util.downloadFile(downloadURL);
// set file information on the GUI
gui.setFileInfo(util.getFileName(), util.getContentLength());
String saveFilePath = saveDirectory + File.separator + util.getFileName();
InputStream inputStream = util.getInputStream();
// opens an output stream to save into file
FileOutputStream outputStream = new FileOutputStream(saveFilePath);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
long totalBytesRead = 0;
int percentCompleted = 0;
long fileSize = util.getContentLength();
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
percentCompleted = (int) (totalBytesRead * 100 / fileSize);
setProgress(percentCompleted);
}
outputStream.close();
util.disconnect();
} catch (IOException ex) {
JOptionPane.showMessageDialog(gui, "Error downloading file: " + ex.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
setProgress(0);
cancel(true);
}
return null;
}
/**
* Executed in Swing's event dispatching thread
*/
@Override
protected void done() {
if (!isCancelled()) {
JOptionPane.showMessageDialog(gui,
"File has been downloaded successfully!", "Message",
JOptionPane.INFORMATION_MESSAGE);
}
}
}
This class implements the javax.swing.SwingWorker class so its doInBackground() method will be executed in a separate thread. It utilizes the HTTPDownloadUtil class to perform the file download, updates file information to the GUI and notifies download progress so the GUI will update the progress bar accordingly.
Code of the SwingFileDownloadHTTP class
package net.codejava.swing.download;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import net.codejava.swing.JFilePicker;
/**
* A Swing application that downloads file from an HTTP server.
* @author www.codejava.net
*
*/
public class SwingFileDownloadHTTP extends JFrame implements
PropertyChangeListener {
private JLabel labelURL = new JLabel("Download URL: ");
private JTextField fieldURL = new JTextField(30);
private JFilePicker filePicker = new JFilePicker("Save in directory: ",
"Browse...");
private JButton buttonDownload = new JButton("Download");
private JLabel labelFileName = new JLabel("File name: ");
private JTextField fieldFileName = new JTextField(20);
private JLabel labelFileSize = new JLabel("File size (bytes): ");
private JTextField fieldFileSize = new JTextField(20);
private JLabel labelProgress = new JLabel("Progress:");
private JProgressBar progressBar = new JProgressBar(0, 100);
public SwingFileDownloadHTTP() {
super("Swing File Download from HTTP server");
// set up layout
setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.WEST;
constraints.insets = new Insets(5, 5, 5, 5);
// set up components
filePicker.setMode(JFilePicker.MODE_SAVE);
filePicker.getFileChooser().setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
buttonDownload.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
buttonDownloadActionPerformed(event);
}
});
fieldFileName.setEditable(false);
fieldFileSize.setEditable(false);
progressBar.setPreferredSize(new Dimension(200, 30));
progressBar.setStringPainted(true);
// add components to the frame
constraints.gridx = 0;
constraints.gridy = 0;
add(labelURL, constraints);
constraints.gridx = 1;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weightx = 1.0;
add(fieldURL, constraints);
constraints.gridx = 0;
constraints.gridy = 1;
constraints.weightx = 0.0;
constraints.gridwidth = 2;
constraints.fill = GridBagConstraints.NONE;
add(filePicker, constraints);
constraints.gridy = 2;
constraints.anchor = GridBagConstraints.CENTER;
add(buttonDownload, constraints);
constraints.gridx = 0;
constraints.gridy = 3;
constraints.gridwidth = 1;
constraints.anchor = GridBagConstraints.WEST;
add(labelFileName, constraints);
constraints.gridx = 1;
add(fieldFileName, constraints);
constraints.gridy = 4;
constraints.gridx = 0;
add(labelFileSize, constraints);
constraints.gridx = 1;
add(fieldFileSize, constraints);
constraints.gridx = 0;
constraints.gridy = 5;
constraints.gridwidth = 1;
constraints.anchor = GridBagConstraints.WEST;
add(labelProgress, constraints);
constraints.gridx = 1;
constraints.weightx = 1.0;
constraints.fill = GridBagConstraints.HORIZONTAL;
add(progressBar, constraints);
pack();
setLocationRelativeTo(null); // center on screen
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
* handle click event of the Upload button
*/
private void buttonDownloadActionPerformed(ActionEvent event) {
String downloadURL = fieldURL.getText();
String saveDir = filePicker.getSelectedFilePath();
// validate input first
if (downloadURL.equals("")) {
JOptionPane.showMessageDialog(this, "Please enter download URL!",
"Error", JOptionPane.ERROR_MESSAGE);
fieldURL.requestFocus();
return;
}
if (saveDir.equals("")) {
JOptionPane.showMessageDialog(this,
"Please choose a directory save file!", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
try {
progressBar.setValue(0);
DownloadTask task = new DownloadTask(this, downloadURL, saveDir);
task.addPropertyChangeListener(this);
task.execute();
} catch (Exception ex) {
JOptionPane.showMessageDialog(this,
"Error executing upload task: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
}
void setFileInfo(String name, int size) {
fieldFileName.setText(name);
fieldFileSize.setText(String.valueOf(size));
}
/**
* Update the progress bar's state whenever the progress of download changes.
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("progress")) {
int progress = (Integer) evt.getNewValue();
progressBar.setValue(progress);
}
}
/**
* Launch the application
*/
public static void main(String[] args) {
try {
// set look and feel to system dependent
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new SwingFileDownloadHTTP().setVisible(true);
}
});
}
}
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import net.codejava.swing.JFilePicker;
/**
* A Swing application that downloads file from an HTTP server.
* @author www.codejava.net
*
*/
public class SwingFileDownloadHTTP extends JFrame implements
PropertyChangeListener {
private JLabel labelURL = new JLabel("Download URL: ");
private JTextField fieldURL = new JTextField(30);
private JFilePicker filePicker = new JFilePicker("Save in directory: ",
"Browse...");
private JButton buttonDownload = new JButton("Download");
private JLabel labelFileName = new JLabel("File name: ");
private JTextField fieldFileName = new JTextField(20);
private JLabel labelFileSize = new JLabel("File size (bytes): ");
private JTextField fieldFileSize = new JTextField(20);
private JLabel labelProgress = new JLabel("Progress:");
private JProgressBar progressBar = new JProgressBar(0, 100);
public SwingFileDownloadHTTP() {
super("Swing File Download from HTTP server");
// set up layout
setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.WEST;
constraints.insets = new Insets(5, 5, 5, 5);
// set up components
filePicker.setMode(JFilePicker.MODE_SAVE);
filePicker.getFileChooser().setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
buttonDownload.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
buttonDownloadActionPerformed(event);
}
});
fieldFileName.setEditable(false);
fieldFileSize.setEditable(false);
progressBar.setPreferredSize(new Dimension(200, 30));
progressBar.setStringPainted(true);
// add components to the frame
constraints.gridx = 0;
constraints.gridy = 0;
add(labelURL, constraints);
constraints.gridx = 1;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weightx = 1.0;
add(fieldURL, constraints);
constraints.gridx = 0;
constraints.gridy = 1;
constraints.weightx = 0.0;
constraints.gridwidth = 2;
constraints.fill = GridBagConstraints.NONE;
add(filePicker, constraints);
constraints.gridy = 2;
constraints.anchor = GridBagConstraints.CENTER;
add(buttonDownload, constraints);
constraints.gridx = 0;
constraints.gridy = 3;
constraints.gridwidth = 1;
constraints.anchor = GridBagConstraints.WEST;
add(labelFileName, constraints);
constraints.gridx = 1;
add(fieldFileName, constraints);
constraints.gridy = 4;
constraints.gridx = 0;
add(labelFileSize, constraints);
constraints.gridx = 1;
add(fieldFileSize, constraints);
constraints.gridx = 0;
constraints.gridy = 5;
constraints.gridwidth = 1;
constraints.anchor = GridBagConstraints.WEST;
add(labelProgress, constraints);
constraints.gridx = 1;
constraints.weightx = 1.0;
constraints.fill = GridBagConstraints.HORIZONTAL;
add(progressBar, constraints);
pack();
setLocationRelativeTo(null); // center on screen
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
* handle click event of the Upload button
*/
private void buttonDownloadActionPerformed(ActionEvent event) {
String downloadURL = fieldURL.getText();
String saveDir = filePicker.getSelectedFilePath();
// validate input first
if (downloadURL.equals("")) {
JOptionPane.showMessageDialog(this, "Please enter download URL!",
"Error", JOptionPane.ERROR_MESSAGE);
fieldURL.requestFocus();
return;
}
if (saveDir.equals("")) {
JOptionPane.showMessageDialog(this,
"Please choose a directory save file!", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
try {
progressBar.setValue(0);
DownloadTask task = new DownloadTask(this, downloadURL, saveDir);
task.addPropertyChangeListener(this);
task.execute();
} catch (Exception ex) {
JOptionPane.showMessageDialog(this,
"Error executing upload task: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
}
void setFileInfo(String name, int size) {
fieldFileName.setText(name);
fieldFileSize.setText(String.valueOf(size));
}
/**
* Update the progress bar's state whenever the progress of download changes.
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("progress")) {
int progress = (Integer) evt.getNewValue();
progressBar.setValue(progress);
}
}
/**
* Launch the application
*/
public static void main(String[] args) {
try {
// set look and feel to system dependent
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new SwingFileDownloadHTTP().setVisible(true);
}
});
}
}
This builds the user interface for the application and wires all the pieces together to form a complete application. To update the progress bar while the download is taking place, it “listens” to the property named “progress” which is repeatedly updated by the DownloadTask class.
Kaynak
Yorumunuzu Ekleyin