【问题标题】:How to use ProgressMonitorInputStream如何使用 ProgressMonitorInputStream
【发布时间】:2014-10-16 01:16:01
【问题描述】:

我知道我一定遗漏了一些非常明显的东西,但是每当我尝试在复制文件时使用 ProgressMonitorInputStream 时,我从来没有收到 ProgressDialog 弹出窗口。

我看到的示例除了将它们的输入流包装在 ProgressMonitorInputStream 中之外似乎没有做太多。

文档说:

这将创建一个进度监视器来监视读取输入流的进度。如果需要一段时间,会弹出一个 ProgressDialog 来通知用户。如果用户点击 Cancel 按钮,则会在下一次读取时抛出 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();
   }
}

有什么建议吗?

【问题讨论】:

    标签: java swing inputstream progressmonitor


    【解决方案1】:

    您在事件调度线程的上下文中调用copyFile,这意味着 EDT 在方法返回之前无法响应新事件或绘制请求。

    尝试将调用放在它自己的 Thread 上下文中...

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

    同样,您可以使用SwingWorker,这有点矫枉过正,但您可以从PropertyChangeListenerdone 方法中受益,该方法可用于重新启用JButton,您是否希望在复制操作正在进行时阻止人们单击按钮

    请参阅Concurrency in SwingWorker 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();
        }
    }
    

    请记住,设置窗口和显示会涉及开销,需要将其考虑在内。系统可能“想要”显示一个窗口,但当系统设置并准备显示时它,steam 可能已经复制完了……

    扩展示例

    nb:我不太喜欢 ProgressMonitor API,因为我无法找到 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) {
            }
        }
    
    }
    

    这试图包含该功能,但也处理done 方法内的ProgressMonitorInputStream 清理,确保它在EDT 内完成。我会亲自附加一个PropertyChangeListener 并监视done 属性以确定工作人员何时完成并检查返回结果以获取任何异常,这使您能够自己处理异常方式并将工作人员与您的流程分离

    【讨论】:

    • 为了写一个简单的问题,我忽略了在我的示例中添加我使用 SwingWorker 类来执行 copyFile 的事实。所以这在我的实际代码中不是问题。我仍然没有得到弹出窗口。不过感谢您的建议!
    • 好吧,提供一个使用SwingWorker的例子,这样我们就可以真正看到你在做什么......
    • 非常感谢您的帮助!
    • 这正是我目前正在尝试的方法。这是错误的 - 大约 50% 的时间,应用程序挂在 close() 调用中。这背后的原因是ProgressMonitorInputStream#close 调用dispose(),并且与所有其他AWT/Swing 方法一样,不应在后台线程上调用它。那么close() 不能在后台线程上调用,必须在 EDT 上调用。我实际上建议克隆ProgressMonitorInputStream,在执行此操作时调用invokeLater,这将是我解决此问题的方法。
    • @Trejkaz 就我个人而言,我会避免使用 ProgressMonitorInputStream,因为我什至看不到它在哪里同步其任何功能。您也可以在 SwingWorker 的 done 方法中调用 close,但这会将工作与我通常不喜欢的复制过程相结合
    【解决方案2】:

    您的程序可以处理文件,但是当涉及到服务器和客户端流时,它 失败。

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

    【讨论】:

      猜你喜欢
      • 2012-01-12
      • 1970-01-01
      • 1970-01-01
      • 2018-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-29
      • 1970-01-01
      相关资源
      最近更新 更多