【问题标题】:Progressbar of a bin file loadingbin文件加载进度条
【发布时间】:2014-06-20 20:14:06
【问题描述】:

如何在加载 bin 文件时显示 JProgressBar 组件?

我只能找到迭代 bin 读取的解决方案,并且我使用的对象读取如下:

CustomObj test = (CustomObj) in.readObject();

干杯

【问题讨论】:

    标签: java swing loading bin


    【解决方案1】:

    如果无法衡量进程的进度,那么只能指定进度条的“不定模式”。在此模式下,进度条会指示它正在工作,但该过程的完成是未知的。

    JProgressBar progress = new JProgressBar();
    progress.setIndeterminate(true);
    

    【讨论】:

      【解决方案2】:

      我建议做两件事:

      1. 围绕原始输入流创建一个包装类,以便您可以监控从中读取的字节。基本上,您扩展 InputStream 并将所有内容委托给原始流(少数方法除外),并在 read() 方法中,确保通知某个侦听器。
      2. 我猜如果你想要一个进度条,这意味着加载操作需要一段时间,你想向用户提供反馈。长时间运行的任务不能直接在 EDT 上运行(因此通常不能在 actionPerformed 方法中执行任务)。因此,您需要将工作委托给另一个线程,例如使用 SwingWorker。如果您不这样做,那么 UI 将冻结,用户将无法查看反馈。

      这个存在,说它可能看起来很复杂或不简单。因此,这里有一些简短的例子,说明了所有这些并且有效:

      import java.awt.BorderLayout;
      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 java.io.InputStream;
      import java.io.ObjectInputStream;
      import java.io.ObjectOutputStream;
      import java.util.ArrayList;
      import java.util.List;
      import java.util.Random;
      
      import javax.swing.JButton;
      import javax.swing.JFrame;
      import javax.swing.JPanel;
      import javax.swing.JProgressBar;
      import javax.swing.SwingUtilities;
      import javax.swing.SwingWorker;
      
      public class TestProgressBar {
      
          // Some simple listener interface to get a callback as bytes are being read
          public static interface ProgressListener {
              public void notifyByteRead();
          }
      
          // The wrapping input stream that will call the listener as bytes are being read
          public static class ProgressInputStream extends InputStream {
      
              private InputStream in;
      
              @Override
              public int read() throws IOException {
                  int read = in.read();
                  if (read > -1) {
                      // Here we notify the listener
                      listener.notifyByteRead();
                  }
                  return read;
              }
      
              @Override
              public long skip(long n) throws IOException {
                  return in.skip(n);
              }
      
              @Override
              public int available() throws IOException {
                  return in.available();
              }
      
              @Override
              public void close() throws IOException {
                  in.close();
              }
      
              @Override
              public void mark(int readlimit) {
                  in.mark(readlimit);
              }
      
              @Override
              public void reset() throws IOException {
                  in.reset();
              }
      
              @Override
              public boolean markSupported() {
                  return in.markSupported();
              }
      
              private ProgressListener listener;
      
              public ProgressInputStream(InputStream in, ProgressListener listener) {
                  this.in = in;
                  this.listener = listener;
              }
          }
      
          public static void main(String[] args) {
              SwingUtilities.invokeLater(new Runnable() {
                  @Override
                  public void run() {
                      init();
                  }
              });
          }
      
          public static void init() {
              // 1. Let's create a big object with lots of data
              List<Long> object = new ArrayList<Long>();
              Random random = new Random();
              for (int i = 0; i < 1e6; i++) {
                  object.add(random.nextLong());
              }
      
              // 2. We write it to a temp file
              File tempFile = null;
              ObjectOutputStream oos = null;
              try {
                  tempFile = File.createTempFile("Test", ".bin");
                  tempFile.deleteOnExit();
                  FileOutputStream fos = new FileOutputStream(tempFile);
                  oos = new ObjectOutputStream(new BufferedOutputStream(fos));
                  oos.writeObject(object);
              } catch (FileNotFoundException e1) {
                  e1.printStackTrace();
              } catch (IOException e1) {
                  e1.printStackTrace();
              } finally {
                  try {
                      if (oos != null) {
                          oos.close();
                      }
                  } catch (IOException e1) {
                      e1.printStackTrace();
                  }
      
              }
              if (tempFile == null) {
                  System.exit(1);
              }
              // 3. Now let's build a UI to load that
              final File theFile = tempFile;
              JFrame frame = new JFrame("Test ghost text");
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              JPanel panel = new JPanel(new BorderLayout());
              final JProgressBar bar = new JProgressBar(0, (int) tempFile.length());
              JButton button = new JButton("load");
              button.addActionListener(new ActionListener() {
      
                  @Override
                  public void actionPerformed(ActionEvent e) {
                      bar.setValue(0);
                      // Declare and implement a Swing worker that will run in another thread
                      SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {
                          @Override
                          protected void process(List<Integer> chunks) {
                              // Here we are on the EDT, so we can safely notify the progressbar
                              super.process(chunks);
                              bar.setValue(bar.getValue() + chunks.size());
                          }
      
                          @Override
                          protected Void doInBackground() throws Exception {
                              // Here we are not in the EDT, we perform the task but don't modify anything in the UI
                              ProgressInputStream pis = new ProgressInputStream(new BufferedInputStream(new FileInputStream(theFile)),
                                      new ProgressListener() {
      
                                          @Override
                                          public void notifyByteRead() {
                                              publish(1); // the value that is sent here could be anything, we don't use it.
                                          }
                                      });
                              ObjectInputStream ois = new ObjectInputStream(pis);
                              try {
                                  List<Long> readObject = (List<Long>) ois.readObject();
                                  System.err.println("Loaded " + readObject.size() + " long values");
                              } catch (Exception e) {
                                  e.printStackTrace();
                              } finally {
                                  pis.close();
                              }
                              return null;
                          }
                      };
                      // Start the worker
                      worker.execute();
                  }
              });
              panel.add(bar);
              panel.add(button, BorderLayout.EAST);
              frame.add(panel);
              frame.pack();
              frame.setVisible(true);
          }
      }
      

      【讨论】:

      • 我会看看,非常感谢你的回答。加载可能会很长,也没有什么可以用于使用进度条将对象输出到 bin 的吗?干杯
      • @user3738319 只是通过扩展 OutputStream 使用相同的原理。
      【解决方案3】:

      子类 java.io.FilteredInputStream 以计算正在读取的字节数并将其插入到您的 ObjectInputStream 和正在读取的底层 InputStream 之间。

      您可以通过对运行计数进行采样或使用子类中内置的回调来更新进度条。

      例子:

      public class CountingInputStream extends FilteredInputStream {
      
          private int numBytes;
      
          public CountingInputStream(InputStream inputStream){
              this(inputStream);
          }
      
          public int getNumBytes(){
              return numBytes;
          }
      
          @Override
          public int read() {
              int b = super.read();
              if(b != -1){
                  countBytes(1);
              }
              return b;
          }
      
          @Override
          public int read(byte[] b){
              int n = super.read(b);
              if(n >= 0){
                 countBytes(n);
              }
              return n;
          }
      
          @Override
          public int read(byte[] b, int off, int len){
              int n = super.read(b, off, len);
              if(n >= 0){
                 countBytes(n);
              }
              return n;
          }    
      
          private void countBytes(int n){
              numBytes += n;
          }
      
      }
      

      它可以像下面这样使用(假设InputStream is你的数据源)。:

      InputStream is = ...;
      CountingInputStream cis = new CountingInputStream(is)
      ObjectInputStream ois = new ObjectInputStream(cis);
      
      ois.readObject();
      

      您可以从不同的线程(可能使用 Swing 计时器)采样 cis.getNumBytes(),并使用返回的值更新 JProgressBar

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多