2013-04-09 19 views
2

我在后端使用Processbuilder在我的Java程序中执行外部进程。我使用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); 
} 
} 

按钮是调用该调用的按钮的名称。但是,我面临的问题是函数调用执行,而不执行这些语句。

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

按钮是函数的执行后被禁止。 1)我可以知道为什么会发生? 2)我可以知道解决方案使进度条指示后端进度,直到它完成吗?

在此先感谢。

+0

我想也许尝试重构这一点,所以它的使用'SwingWorker' – Franklin 2013-04-09 12:21:46

回答

0

它被执行,但它在与GUI相同的线程中执行,所以视图不会被更新。

显示ProgressBar并禁用Button后,启动一个等待Process完成的runnable。

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

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

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

好感谢。会尝试。 – sreram 2013-04-09 12:27:36

+0

现在能够获得进度监视器,但控件不会进入该功能(执行)。 – sreram 2013-04-09 12:54:04

+0

你是否开始()线程?我编辑了我的答案,包括一个未经测试的例子,我将如何尝试这样做。 – MaPePeR 2013-04-09 12:59:16

2

我建议使用一个SwingWorker。这是为了解决这个问题。这是从我的代码库的一些代码片段(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