简体   繁体   English

Swing(Java)中的进度条用于命令工具

[英]Progress bar in Swing (Java) for command tools

I have several C/C++ command line tools that I'm wrapping with Java.Swing as GUI. 我有几个C / C ++命令行工具,我用Java.Swing作为GUI包装。 The command line tools can take minutes to hours. 命令行工具可能需要几分钟到几小时。 Progress bar seems like a good idea to keep users sane. 进度条似乎是让用户保持理智的好主意。 I'm also thinking it might be nice to wrap a GUI for the progress bar, instead of just using system out. 我也认为为进度条包装GUI可能不错,而不仅仅是使用系统输出。 But how? 但是怎么样?

I'm thinking the command line tools can write percents to stderr and I can somehow read it in java. 我认为命令行工具可以将百分比写入stderr,我可以在java中以某种方式读取它。 Not exactly sure what the mechanics for this would be. 不完全确定这个的机制是什么。 I'm also not clear on asynchronous display (learned a bit about invokeLater() ). 我也不清楚异步显示(了解一下invokeLater())。 New to Java, and would appreciate general suggestions as well. Java新手,也欢迎一般性建议。 Thanks. 谢谢。

--- update --- ---更新---

Thanks everyone for your suggestions. 谢谢大家的建议。 Here's the resulting code. 这是结果代码。

private void redirectSystemStreams() {
    OutputStream out_stderr = new OutputStream() {
      @Override
      public void write(final int b) throws IOException {
        update(String.valueOf((char) b));
      }
      @Override
      public void write(byte[] b, int off, int len) throws IOException {
        update(new String(b, off, len));
      }
      @Override
      public void write(byte[] b) throws IOException {
        write(b, 0, b.length);
      }
    };
    System.setErr(new PrintStream(out_stderr, true));
}

private void update(final String inputText) {
    int value = 20; //parse inputText; make sure your executable calls fflush(stderr) after each fprintf().
    jProgressBar.setValue(value);

    /* Also one can redirect to a textpane
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        //update jTextPane with inputText
      }
    });
    */
}

That's seems very fragile, better would be to communicate via sockets in a well established protocol or with some sort of RCP ( perhaps Google's protobuf ) or even webservices. 这似乎非常脆弱,更好的是通过套接字在一个完善的协议或某种RCP(可能是谷歌的protobuf)甚至网络服务进行通信。

If you still insists you can launch a process in Java with ProcessBuilder that will give you a Process reference of which you can get the InputStream to read the standard output, but again, that seems very fragile to me. 如果你仍然坚持认为你可以使用ProcessBuilder在Java中启动一个进程,它将为你提供一个Process引用,你可以让InputStream读取标准输出,但同样,这对我来说似乎非常脆弱。

I hope this helps. 我希望这有帮助。

For the progress bar part of your problem you can do something like the following. 对于问题的进度条部分,您可以执行以下操作。 Note that this is just an example to illustrate the point. 请注意,这只是一个例子来说明这一点。

Basically, a thread is created to do the work. 基本上,创建一个线程来完成工作。 Presumably this Runner thread will be interacting with your C/C++ code to get its progress. 据推测,这个Runner线程将与您的C / C ++代码进行交互以获得进展。 It then calls update on the Progress Bars Dialog class. 然后它调用Progress Bars Dialog类的update。

   import java.awt.BorderLayout;
   import java.awt.Dimension;
   import javax.swing.JDialog;
   import javax.swing.JFrame;
   import javax.swing.JLabel;
   import javax.swing.JPanel;
   import javax.swing.JProgressBar;

  public class Main {

   private int value;
   private Progress pbar;

   public static void main(String args[]) {
      new Main();
   }

   public Main() {        

     pbar = new Progress();
     Thread t = new Thread(new Runner());
     t.start();

  }

  class Progress extends JDialog {

    JProgressBar pb;
    JLabel label;

    public Progress() {
        super((JFrame) null, "Task In Progress");
        pb = new JProgressBar(0, 100);
        pb.setPreferredSize(new Dimension(175, 20));
        pb.setString("Working");
        pb.setStringPainted(true);
        pb.setValue(0);


        label = new JLabel("Progress: ");

        JPanel panel = new JPanel();
        panel.add(label);
        panel.add(pb);
        add(panel, BorderLayout.CENTER);
        pack();
        setVisible(true);
    }

    public void update(){
        pb.setValue(value);

        if(value >= 100){
            this.setVisible(false);
            this.dispose();
        }
    }
}

class Runner implements Runnable {

    public void run() {
        for (int i = 0; i <= 100; i++) {
            value++;
            pbar.update();
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
            }
        }
     }
   }
 }
// Create a window
JFrame frame = new JFrame("Progress");
// Creates a progress bar and add it to the window
JProgressBar prog = new JProgressBar();
frame.add(prog);
// Run C/C++ application
try {
   Process p = Runtime.getRuntime().exec(new String[]{"filename","arg1","arg2","..."});
   // Get InputStream
   BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
   // Update the progress when recieving output from C/C++
   new java.util.Timer().schedule(new TimerTask(){
       public void run(){
          String str = "";
          while ((str=br.readLine()!=null) {
             prog.setValue(new Integer(str)); // Set Value of Progress Bar
             prog.setString(str+"%"); // Set Value to display (in text) on Progress Bar
          }
       }
   },0,100); // Check every 100 milliseconds
   // Fit the window to its contents and display it
   frame.pack();
   frame.setVisible(true);
 } catch (Exception e) {
    System.out.println("Failed To Launch Program or Failed To Get Input Stream");
 }

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

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