hax*_*ode 3 java swing inputstream progressmonitor
我知道我必须遗漏一些非常明显的东西,但每当我在复制文件时尝试使用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();
}
}
Run Code Online (Sandbox Code Playgroud)
有什么建议?
您正在copyFile事件调度线程的上下文中调用,这意味着在方法返回之前,EDT无法响应新事件或绘制请求.
尝试将呼叫置于其自己的Thread上下文中......
Thread t = new Thread(new Runnable(
public void run() {
copyFile();
}
));
t.start();
Run Code Online (Sandbox Code Playgroud)
同样,你可以使用SwingWorker,这是矫枉过正的一点点,但你得到的利益PropertyChangeListener或它的done方法,它可以用来重新启用JButton,你应该想阻止人们点击按钮同时复制操作进行中
有关更多详细信息,请参阅Swing和工作线程中的并发和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();
}
}
Run Code Online (Sandbox Code Playgroud)
请记住,设置窗口和显示需要花费开销,这需要考虑因素.系统可能"想要"显示窗口,但是当系统设置好并准备显示它时,蒸汽可能已完成复制......
扩展示例
nb:我不太喜欢ProgressMonitorAPI,因为我无法找到UI与EDT同步的位置,这可能会导致Java 7和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) {
}
}
}
Run Code Online (Sandbox Code Playgroud)
这试图包含功能,但也处理方法ProgressMonitorInputStream内部的清理done,确保它在EDT内完成.我个人会附上一个PropertyChangeListener并监控该done属性,以确定工人何时完成并检查返回结果以便获取任何异常,这使您能够以自己的方式处理异常并将其分离.你的过程中的工人