2009-08-07 35 views
2

我真的不熟悉使用线程,所以我希望有人能帮助我找出最好的方法来做到这一点。使用线程和ProcessBuilder

我在我的java应用程序中有一个JButton ...当你点击按钮时,我有一个Process Builder创建一个执行一些外部python代码的进程。 python代码生成一些文件,这可能需要一些时间。当python代码完成执行时,我需要将这些文件加载​​到我的Java应用程序中的一个applet中。

在其当前形式中,我在调用外部python文件的代码中有一个p.waitFor()...所以当你点击按钮时,按钮会挂起(整个应用程序实际挂起),直到进程已经完成了。显然,我希望用户能够在该过程正在进行时与应用程序的其余部分进行交互,但一旦完成,我希望我的应用程序知道它,以便它可以将文件加载到小程序中。

这样做的最好方法是什么?

感谢您的帮助。

回答

9

您应该使用SwingWorker在后台线程上调用Python进程。这样,在长时间运行的任务运行时,您的用户界面将保持响应。

// Define Action. 
Action action = new AbstractAction("Do It") { 
    public void actionPerformed(ActionEvent e) { 
    runBackgroundTask(); 
    } 
} 

// Install Action into JButton. 
JButton btn = new JButton(action); 

private void runBackgroundTask() { 
    new SwingWorker<Void, Void>() { 
    { 
     // Disable action until task is complete to prevent concurrent tasks. 
     action.setEnabled(false); 
    } 

    // Called on the Swing thread when background task completes. 
    protected void done() { 
     action.setEnabled(true); 

     try { 
     // No result but calling get() will propagate any exceptions onto Swing thread. 
     get(); 
     } catch(Exception ex) { 
     // Handle exception 
     } 
    } 

    // Called on background thread 
    protected Void doInBackground() throws Exception { 
     // Add ProcessBuilder code here! 
     return null; // No result so simply return null. 
    } 
    }.execute(); 
} 
+0

非常感谢。我甚至不知道SwingWorker存在......但它完美运作。 – knt 2009-08-07 20:02:09

0

你真的想创建一个新线程来监视你的新进程。正如你发现的那样,对于UI和监控子进程只使用一个线程将会使子进程在运行时看起来挂起。

下面是假定log4j的记录,我认为会说明一个可能的方法存在一些示例代码...

Runtime runtime = Runtime.getRuntime(); 
String[] command = { "myShellCommand", "firstArgument" }; 

try { 

    boolean done = false; 
    int exitValue = 0; 
    Process proc = runtime.exec(command); 

    while (!done) { 
     try { 
      exitValue = proc.exitValue(); 
      done = true; 
     } catch (IllegalThreadStateException e) { 
      // This exception will be thrown only if the process is still running 
      // because exitValue() will not be a valid method call yet... 
      logger.info("Process is still running...") 
     } 
    } 

    if (exitValue != 0) { 
     // Child process exited with non-zero exit code - do something about failure. 
     logger.info("Deletion failure - exit code " + exitValue); 
    } 

} catch (IOException e) { 
    // An exception thrown by runtime.exec() which would mean myShellCommand was not 
    // found in the path or something like that... 
    logger.info("Deletion failure - error: " + e.getMessage()); 
} 

// If no errors were caught above, the child is now finished with a zero exit code 
// Move on happily 
+0

对于隐含Swing的JButton并没有太多的考虑 - 这是一种更通用的方法,它可以和SWT或控制台应用程序一样工作...... – jharlap 2009-08-07 17:20:45

+0

你说应该创建一个新的线程,但是你的例子没有演示这个。您还应该使用[ProcessBuilder](http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html)。 – 2014-06-28 06:31:11