我知道我必须遗漏一些非常明显的东西,但每当我在复制文件时尝试使用ProgressMonitorInputStream时,我都不会得到ProgressDialog弹出窗口。
我看到的示例除了将它们的输入流包装在ProgressMonitorInputStream中之外似乎没什么用。
文档说:
这将创建一个进度监视器来监视读取输入流的进度。如果需要一段时间,将弹出ProgressDialog以通知用户。如果用户点击取消按钮,则下次读取时将抛出InterruptedIOException。当流关闭时,所有正确的清理工作都已完成。
这是一个非常简单的例子,即使我setMillisToPopup()
到一个非常小的数字,我也不会弹出带有大文件的对话框。
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();
}
}
有什么建议吗?
答案 0 :(得分:5)
您正在事件调度线程的上下文中调用copyFile
,这意味着在方法返回之前,EDT无法响应新事件或绘制请求。
尝试将呼叫置于其自己的Thread
上下文...
Thread t = new Thread(new Runnable(
public void run() {
copyFile();
}
));
t.start();
同样地,您可以使用SwingWorker
,这有点过分,但您可以获得PropertyChangeListener
或done
方法的好处,可以用来重新启用JButton
,是否要阻止人们在复制操作过程中单击按钮
有关详细信息,请参阅Concurrency in Swing和Worker Threads and SwingWorker
更新了示例
在本地磁盘上复制371mb文件......
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);
}
public void go() {
this.setLocationRelativeTo(null);
this.setVisible(true);
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void copyFile() {
File file = new File("...");
BufferedInputStream bis;
BufferedOutputStream baos;
try {
bis = new BufferedInputStream(new FileInputStream(file));
ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(
this,
"Reading... " + file.getAbsolutePath(),
bis);
pmis.getProgressMonitor().setMillisToPopup(10);
baos = new BufferedOutputStream(new FileOutputStream("..."));
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();
}
}
private class ButtonActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false);
SwingWorker worker = new SwingWorker() {
@Override
protected Object doInBackground() throws Exception {
copyFile();
return null;
}
@Override
protected void done() {
button.setEnabled(true);
}
};
worker.execute();
}
}
public static void main(String[] args) {
ProgressBarDemo demo = new ProgressBarDemo();
demo.go();
}
}
请记住,设置窗口和显示需要花费开销,需要将其考虑在内。系统可能“想要”显示窗口,但是当系统设置好并准备显示时它,蒸汽可能已完成复制......
扩展示例
nb:我真的不喜欢ProgressMonitor
API,因为我无法找到UI与EDT同步的位置,这可能会导致Java 7和Java中出现问题。 8
你可以将这个想法形式化为一个自成一体的工人,例如......
public class CopyWorker extends SwingWorker {
private File source;
private File dest;
private Component parent;
private ProgressMonitorInputStream pmis;
public CopyWorker(Component parent, File source, File dest) {
this.parent = parent;
this.source = source;
this.dest = dest;
}
@Override
protected Object doInBackground() throws Exception {
try (InputStream is = new FileInputStream(source)) {
try (OutputStream os = new FileOutputStream(dest)) {
pmis = new ProgressMonitorInputStream(
parent,
"Copying...",
is);
pmis.getProgressMonitor().setMillisToPopup(10);
byte[] buffer = new byte[2048];
int nRead = 0;
while ((nRead = pmis.read(buffer)) != -1) {
os.write(buffer, 0, nRead);
}
}
}
return null;
}
@Override
protected void done() {
try {
pmis.close();
} catch (Exception e) {
}
}
}
这会尝试包含该功能,但也会处理ProgressMonitorInputStream
方法中done
的清理工作,确保它在EDT中完成。我个人会附加PropertyChangeListener
并监视done
属性以确定工作人员何时完成并检查返回结果以便获取任何异常,这使您能够处理以您自己的方式例外,并将工人与您的流程分开
答案 1 :(得分:0)
您的程序可以处理文件,但是涉及服务器和客户端流时, 失败。
import java.awt.FlowLayout;
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.FileOutputStream;
import java.io.IOException;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.ProgressMonitorInputStream;
import javax.swing.SwingWorker;
public class FileReceive extends JFrame {
private static final long serialVersionUID = 1L;
private BufferedInputStream bufferInput;
private FileOutputStream fout;
private BufferedOutputStream bufferOutput;
private Socket client;
private JButton button;
private File fileinfo;
ProgressMonitorInputStream pois;
FileReceive() {
setLocationRelativeTo(null);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
receiveFile();
}
public static void main(String arg[]) {
new FileReceive();
}
public void receiveFile() {
try {
fileinfo=new File(filepath);
client=new Socket("localhost",9090);
fout=new FileOutputStream(fileinfo);
bufferOutput=new BufferedOutputStream(fout);
bufferInput=new BufferedInputStream(client.getInputStream());
pois=new ProgressMonitorInputStream(this, "reading", bufferInput);
int ch;
byte[] b=new byte[2048];
System.out.println("Receiving File");
while(-1!=(ch=pois.read(b))) {
bufferOutput.write(b,0,ch);
}
pois.close();
bufferInput.close();
bufferOutput.close();
fout.close();
client.close();
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e.getMessage());
}
}
}