I know I must be missing something very obvious, but whenever I try to use the ProgressMonitorInputStream when copying a file, I never get the ProgressDialog popup.
The examples I see don't seem to do much other than wrap their input stream within the ProgressMonitorInputStream.
The docs say:
This creates a progress monitor to monitor the progress of reading the input stream. If it's taking a while, a ProgressDialog will be popped up to inform the user. If the user hits the Cancel button an InterruptedIOException will be thrown on the next read. All the right cleanup is done when the stream is closed.
Here is an extremely simple example I put together that never pops up the dialog with a large file even if I setMillisToPopup() to an insanely small number.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.ProgressMonitorInputStream;
import javax.swing.SwingWorker;
public class ProgressBarDemo extends JFrame {
private static final long serialVersionUID = 1L;
private JButton button;
ProgressBarDemo()
{
button = new JButton("Click me!");
ButtonActionListener bal = new ButtonActionListener();
button.addActionListener(bal);
this.getContentPane().add(button);
}
private class ButtonActionListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
Worker worker = new Worker();
worker.execute();
button.setEnabled(false);
}
}
public void go() {
this.setLocationRelativeTo(null);
this.setVisible(true);
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private class Worker extends SwingWorker<Void, Void>
{
private void copyFile() {
File file = new File("/Users/mypath/Desktop/WirelessDiagnostics.tar.gz");
BufferedInputStream bis;
BufferedOutputStream baos;
try {
bis = new BufferedInputStream(new FileInputStream(file));
ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(
ProgressBarDemo.this,
"Reading... " + file.getAbsolutePath(),
bis);
pmis.getProgressMonitor().setMillisToPopup(10);
baos = new BufferedOutputStream(new FileOutputStream("/Users/mypath/Desktop/NewWirelessDiagnostics.tar.gz"));
byte[] buffer = new byte[2048];
int nRead = 0;
while((nRead = pmis.read(buffer)) != -1) {
baos.write(buffer, 0, nRead);
}
pmis.close();
baos.flush();
baos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected Void doInBackground() throws Exception {
// TODO Auto-generated method stub
copyFile();
return null;
}
@Override
protected void done() {
button.setEnabled(true);
}
}
}
public class TestProj {
public static void main(String[] args) {
ProgressBarDemo demo = new ProgressBarDemo();
demo.go();
}
}
Any suggestions?
You are calling
copyFilefrom within the context of the Event Dispatching Thread, this means the EDT is unable to respond to new events or paint requests until after the method returns.Try placing the call within it's own
Threadcontext...Equally, you could use a
SwingWorker, it's a little bit of overkill, but you get the benefit of thePropertyChangeListeneror it'sdonemethod, which could be used to re-enable theJButton, should you want to prevent people from clicking the button while a copy operation is in progressSee Concurrency in Swing and Worker Threads and SwingWorker for more details
Updated with example
Copying a 371mb file, across the local disk...
Remember, there is overhead involved in setting up the window and displaying, which needs to be factored in. The system may "want" to display a window, but by the time the system has set it up and is prepared to display it, the steam may have finished copying...
Extended Example
nb: I don't really like the
ProgressMonitorAPI as I've not been able to find where the UI is synchronised with the EDT, this can cause issues in Java 7 & 8You could formalise the idea into a self contained worker, for example...
This attempts to contain the functionality, but also deals with the cleanup of the
ProgressMonitorInputStreamwithin thedonemethod, making sure that it's done within the EDT. I'd personally attach aPropertyChangeListenerto it and monitor thedoneproperty to determine when the worker has completed and examine the return result in order to pick up any exceptions, this gives you the ability to handle the exceptions in your own way and de-couples the worker from your process