【问题标题】:Progress monitor (Indeterminate) to show execution happens at backend进度监视器(不确定)显示执行发生在后端
【发布时间】:2013-04-09 12:16:39
【问题描述】:

我正在使用我的 java 程序中的 Processbuilder 在后端执行一个外部进程。我正在使用 process.waitFor 来获取进程的退出状态。后端进程将花费时间,这取决于所提供的输入。所以我需要为不确定的时间制作一个进度条,直到进程完成。这只是为了通知用户后端有一个进程。

    try {
        button.setEnabled(false);
        this.progressbar.setVisible(true);
        this.progressbar.setIndeterminate(true);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        perform(this);
    }
}                                    

public void perform(JFrame f)
{
            String cmd[]={"cmd", "/c","a.exe:};
            ProcessBuilder pb = new ProcessBuilder(cmd);
            pb.directory(new File(dir_path));
            pb.redirectErrorStream(true);
            try {
                    p = pb.start();
                } catch (IOException ex) {
                    Logger.getLogger(execution.class.getName()).log(Level.SEVERE, null, ex);
                       }
            try
            {
               int exitVal = p.waitFor();
               if(exitVal>0)
               {
                   this.progressbar.setVisible(false);
                   this.progressbar.setIndeterminate(false);
                   this.button.setEnabled(true);
               }
               if(p.waitFor()==0)
               {
                   this.progressbar.setVisible(false);
                   this.progressbar.setIndeterminate(false);

                   JOptionPane.showMessageDialog(f,"Scan completed successfully.");
               }
             } catch (InterruptedException ex) {
    Logger.getLogger(execution.class.getName()).log(Level.SEVERE, null, ex);
}
}

Button 是调用调用的按钮的名称。但是我面临的问题是函数调用 perform 是在没有执行这些语句的情况下进行的。

    try {
        button.setEnabled(false);
        this.progressbar.setVisible(true);
        this.progressbar.setIndeterminate(true);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

该功能执行后按钮被禁用。 1)我可以知道为什么会这样吗? 2) 我可以知道在完成之前制作进度条指示后端进度的解决方案吗?

提前致谢。

【问题讨论】:

  • 我可能会尝试重构它,所以它使用SwingWorker

标签: java multithreading process progress-bar processbuilder


【解决方案1】:

我建议使用SwingWorker。它是为诸如此类的问题而设计的。这是我代码库中一些代码的 sn-p(vui 是一个 JFrame):

vui.clearOutput();
vui.setOutput("Waiting for items to copy...\n"
            + "This could take several minutes. Please standby...");
vui.disableExit();
vui.disableInput();
vui.disableNext();
vui.showProgressBar();

// make thread so you can disable all options when zipping and enable progress bar
SwingWorker transferWorker = new SwingWorker() {
    @Override
    protected Void doInBackground() throws Exception {
        try {
            Process p = Runtime.getRuntime().exec("resources/bin/transferCopier.bat");

            StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "ERROR");
            StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), "OUTPUT");
            errorGobbler.start();
            outputGobbler.start();

            p.waitFor();
        } catch (IOException ex) {
            Logger.getLogger(VaderController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InterruptedException ie) {
            Logger.getLogger(VaderController.class.getName()).log(Level.SEVERE, null, ie);
        }
        return null;
    }
    @Override
    public void done() {
        vui.hideProgressBar();
        vui.clearOutput();
        vui.setOutput("Transfer Complete!\n\n"
                    + "Push \"Exit\" to quit.\n\n");
        vui.enableExit();
        mode = VaderMode.END;
    }
};
transferWorker.execute();

当执行transferWorker.execute(); 时,会调用doInBackground()。一旦doInBackground() 完成计算,done() 就会被调用。 done() 是您对 GUI 进行任何最终更新的地方。

关于我上面的代码需要注意的关键点是,我在执行SwingWorker 之前启用了进度条,然后当SwingWorker 完成执行时,我禁用了进度条。

资源:

http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

【讨论】:

    【解决方案2】:

    它被执行了,但是它和GUI在同一个线程中执行,所以视图没有得到更新。

    在显示 ProgressBar 并禁用 Button 后,启动一个等待进程完成的可运行对象。

    只需将 perform() 包装在 Runnable 中。

    未经测试的代码: 你写的不是perform(this)

    new Thread(new Runnable() { 
        public void run() {
            perform(YourClassName.this);
        }
    }).start();
    

    【讨论】:

    • 现在可以获取进度监视器,但控件没有转到功能(执行)。
    • start() 线程了吗?我编辑了我的答案以包含一个未经测试的示例,我将如何尝试这样做。
    猜你喜欢
    • 1970-01-01
    • 2019-01-28
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    • 2012-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多