2009-08-07 8 views
2

Je ne suis vraiment pas familier avec les threads, alors j'espérais que quelqu'un puisse m'aider à trouver la meilleure façon de faire.Utilisation de threads et ProcessBuilder

J'ai un JButton dans mon application java ... quand vous cliquez sur le bouton, j'ai un Process Builder qui crée un processus qui exécute du code python externe. Le code python génère des fichiers, ce qui peut prendre du temps. Lorsque le code python est terminé, j'ai besoin de charger ces fichiers dans une applet dans mon application Java. Dans sa forme actuelle, j'ai un p.waitFor() dans le code qui appelle le fichier python externe ... donc quand vous cliquez sur le bouton, le bouton se bloque (l'application entière se bloque) jusqu'à ce que le processus est fait. Évidemment, je veux que l'utilisateur puisse interagir avec le reste de l'application pendant que ce processus est en cours, mais dès que c'est fait, je veux que mon application le sache, afin qu'elle puisse charger les fichiers dans l'applet .

Quelle est la meilleure façon de faire cela?

Merci pour votre aide.

Répondre

9

Vous devez utiliser SwingWorker pour appeler le processus Python sur un thread d'arrière-plan. De cette façon, votre interface utilisateur restera réactive pendant la durée de la tâche.

// 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

Merci beaucoup. Je ne savais même pas que SwingWorker existait ... mais ça fonctionnait parfaitement. – knt

0

Vous voulez vraiment créer un nouveau thread pour surveiller votre nouveau processus. Comme vous l'avez découvert, l'utilisation d'un seul thread à la fois pour l'interface utilisateur et la surveillance du processus enfant fait que l'interface utilisateur semble se bloquer pendant l'exécution du processus enfant.

Voici quelques exemples de code qui suppose l'existence d'un enregistreur de log4j que je pense illustrera une approche possible ...

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

Je ne pensais pas beaucoup au JButton impliquant Swing - il s'agit d'une approche un peu plus générique qui fonctionnerait également avec les applications SWT ou console ... – jharlap

+0

Vous dites qu'un nouveau thread doit être créé, mais votre exemple ne montre pas ce. Vous devriez également utiliser [ProcessBuilder] (http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html). –