简体   繁体   English

如何使用ProgressMonitorInputStream

[英]How to use ProgressMonitorInputStream

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. 我知道我必须遗漏一些非常明显的东西,但每当我在复制文件时尝试使用ProgressMonitorInputStream时,我都不会得到ProgressDialog弹出窗口。

The examples I see don't seem to do much other than wrap their input stream within the ProgressMonitorInputStream. 我看到的示例除了将它们的输入流包装在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. 如果需要一段时间,将弹出ProgressDialog以通知用户。 If the user hits the Cancel button an InterruptedIOException will be thrown on the next read. 如果用户点击取消按钮,则下次读取时将抛出InterruptedIOException。 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. 这是一个非常简单的例子,即使我将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();
   }
}

Any suggestions? 有什么建议?

You are calling copyFile from 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. 您正在Event Dispatching Thread的上下文中调用copyFile ,这意味着在方法返回之前,EDT无法响应新事件或绘制请求。

Try placing the call within it's own Thread context... 尝试将调用置于其自己的Thread上下文中...

Thread t = new Thread(new Runnable(
    public void run() {
        copyFile();
    }
));
t.start();

Equally, you could use a SwingWorker , it's a little bit of overkill, but you get the benefit of the PropertyChangeListener or it's done method, which could be used to re-enable the JButton , should you want to prevent people from clicking the button while a copy operation is in progress 同样地,你可以使用SwingWorker ,这有点过分,但你可以获得PropertyChangeListener或它的done方法的好处,它可以用来重新启用JButton ,如果你想阻止人们点击按钮的话复制操作正在进行中

See Concurrency in Swing and Worker Threads and SwingWorker for more details 有关更多详细信息,请参阅Swing工作线程中的 并发 和SwingWorker

Updated with example 更新了示例

Copying a 371mb file, across the local disk... 在本地磁盘上复制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();
    }
}

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 ProgressMonitor API as I've not been able to find where the UI is synchronised with the EDT, this can cause issues in Java 7 & 8 nb:我真的不喜欢ProgressMonitor API,因为我无法找到UI与EDT同步的位置,这可能会导致Java 7和8中出现问题

You could formalise the idea into a self contained worker, for example... 你可以将这个想法形式化为一个自成一体的工人,例如......

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) {
        }
    }

}

This attempts to contain the functionality, but also deals with the cleanup of the ProgressMonitorInputStream within the done method, making sure that it's done within the EDT. 这会尝试包含该功能,但也会在done方法中处理ProgressMonitorInputStream的清理,确保它在EDT中完成。 I'd personally attach a PropertyChangeListener to it and monitor the done property 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 我个人将一个PropertyChangeListener附加到它并监视done属性以确定worker何时完成并检查返回结果以便获取任何异常,这使您能够以自己的方式处理异常并且将工人与您的过程结合起来

Your program works on files, but when it comes to server and client streams, it fails. 您的程序适用于文件,但是当涉及到服务器和客户端流时,它会失败。

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());
        } 
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM