Reputation: 51
My question is, how do we achieve putting some progress bar or progress monitoring in unzipping zip file
using ZIP4j library and the .extractAll
method. I've done a research about this but I did not find any solution for this or maybe I didn't meet the right answer on internet, and I'm here now to ask anyone on how to do it. I'm using GUI Swing framework for testing only. I hope someone can lend their hand answering it. Thank you!
Upvotes: 0
Views: 695
Reputation: 347204
To my surprise, Zip4J actually has a reasonable concept of a "progression"!
There's a number of ways you might make this work with Swing, but probably the easiest is to use a SwingWorker
, which also has a concept of "progression"
See...
for more details
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.progress.ProgressMonitor;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (ZipException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class TestPane extends JPanel {
private JProgressBar progressBar;
public TestPane() throws ZipException {
progressBar = new JProgressBar();
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new GridBagLayout());
add(progressBar);
ZipFile zipFile = new ZipFile(new File("Test.zip"));
ProgressMonitor monitor = zipFile.getProgressMonitor();
zipFile.setRunInThread(true);
Zip4JZorker worker = new Zip4JZorker(monitor);
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
Object newValue = evt.getNewValue();
System.out.println(propertyName + "/" + newValue);
if ("progress".equals(propertyName) && newValue instanceof Integer) {
int progress = (int) newValue;
progressBar.setValue(progress);
} else if ("state".equals(propertyName) && newValue instanceof SwingWorker.StateValue) {
SwingWorker.StateValue state = (SwingWorker.StateValue) newValue;
if (state == SwingWorker.StateValue.DONE) {
try {
((SwingWorker)evt.getSource()).get();
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(TestPane.this, "Operation failed", "Error", JOptionPane.ERROR_MESSAGE);
}
}
}
}
});
zipFile.addFolder(new File("/some/folder/you/want/zipped"));
worker.execute();
}
}
public class Zip4JZorker extends SwingWorker<Void, Void> {
private ProgressMonitor progressMonitor;
public Zip4JZorker(ProgressMonitor progressMonitor) {
this.progressMonitor = progressMonitor;
}
@Override
protected Void doInBackground() throws Exception {
while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
//System.out.println("Percentage done: " + progressMonitor.getPercentDone());
//System.out.println("Current file: " + progressMonitor.getFileName());
//System.out.println("Current task: " + progressMonitor.getCurrentTask());
// You could pass on some information to the UI via the
// publish method
setProgress(progressMonitor.getPercentDone());
Thread.sleep(100);
}
// Again, you could pass on additional information to the
// UI via the publish method
if (progressMonitor.getResult().equals(ProgressMonitor.Result.SUCCESS)) {
System.out.println("Successfully added folder to zip");
} else if (progressMonitor.getResult().equals(ProgressMonitor.Result.ERROR)) {
throw progressMonitor.getException();
} else if (progressMonitor.getResult().equals(ProgressMonitor.Result.CANCELLED)) {
System.out.println("Task cancelled");
}
return null;
}
}
}
Okay, before anyone asks, what's the difference between this an @Abra's answer, the basic answer is, I use setProgress
over publish
.
publish
can then be used to provide additional details, like the current file being processed. This is just a different way to approach the same problem 😉
Upvotes: 1
Reputation: 20914
I presume you are referring to this Zip4J.
Here is a demo Swing app that hopefully does what you want.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.progress.ProgressMonitor;
public class Zip4jGui implements Runnable {
private JFileChooser fileChooser;
private JFrame frame;
private JProgressBar progressBar;
private JTextField zipFileTextField;
@Override
public void run() {
createAndDisplayGui();
}
private void browseFiles(ActionEvent event) {
if (fileChooser == null) {
fileChooser = new JFileChooser();
}
int choice = fileChooser.showOpenDialog(frame);
if (choice == JFileChooser.APPROVE_OPTION) {
File zipFile = fileChooser.getSelectedFile();
zipFileTextField.setText(zipFile.getAbsolutePath());
}
}
private void createAndDisplayGui() {
frame = new JFrame("Zip4J");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createProgressPanel(), BorderLayout.PAGE_START);
frame.add(createFilePanel(), BorderLayout.CENTER);
frame.add(createButtonsPanel(), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createButtonsPanel() {
JPanel buttonsPanel = new JPanel();
JButton extractButton = new JButton("Extract");
extractButton.addActionListener(this::extractZip);
buttonsPanel.add(extractButton);
return buttonsPanel;
}
private JPanel createFilePanel() {
JPanel filePanel = new JPanel();
JLabel zipFileLabel = new JLabel("ZIP File");
filePanel.add(zipFileLabel);
zipFileTextField = new JTextField(20);
filePanel.add(zipFileTextField);
JButton browseButton = new JButton("Browse...");
browseButton.addActionListener(this::browseFiles);
filePanel.add(browseButton);
return filePanel;
}
private JPanel createProgressPanel() {
JPanel progressPanel = new JPanel();
JLabel progressLabel = new JLabel("Progress");
progressPanel.add(progressLabel);
progressBar = new JProgressBar(0, 100);
progressPanel.add(progressBar);
return progressPanel;
}
private void extractZip(ActionEvent event) {
XtrctTsk task = new XtrctTsk();
task.execute();
}
private class XtrctTsk extends SwingWorker<Void, Integer> {
private ProgressMonitor progressMonitor;
@Override
protected Void doInBackground() throws Exception {
String path = zipFileTextField.getText();
File f = new File(path);
try (ZipFile zipFile = new ZipFile(f)) {
progressMonitor = zipFile.getProgressMonitor();
zipFile.setRunInThread(true);
File dir = f.getParentFile();
zipFile.extractAll(dir.getAbsolutePath());
while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
int done = progressMonitor.getPercentDone();
System.out.println("done: " + done);
publish(done);
try {
Thread.sleep(100);
}
catch (InterruptedException xInterrupted) {
// Safe to ignore (I think).
// xInterrupted.printStackTrace();
}
}
}
return null;
}
protected void done() {
progressBar.setValue(100);
JOptionPane.showMessageDialog(frame,
"Extraction ended.",
progressMonitor.getResult().toString(),
JOptionPane.INFORMATION_MESSAGE);
}
protected void process(List<Integer> percents) {
System.out.println("percents = " + percents);
if (percents != null) {
int size = percents.size();
System.out.println("size = " + size);
if (size > 0) {
progressBar.setValue(percents.get(size - 1));
}
}
}
}
public static void main(String[] args) {
Zip4jGui instance = new Zip4jGui();
EventQueue.invokeLater(instance);
}
}
This is how it looks when I run it.
Refer to the following.
Upvotes: 3