Pierre Carceller
Pierre Carceller

Reputation: 35

Launching python script from javafx app

I want to launch some python scripts from a javafx app. To launch the scripts I use this code :

private String executeCommand(String command) {
    StringBuffer output = new StringBuffer();
    Process p;
    try {
        System.out.println(command);
        p = Runtime.getRuntime().exec(command);
        p.waitFor();
        BufferedReader reader =
                new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line = "";
        while ((line = reader.readLine())!= null) {
            output.append(line + "\n");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return output.toString();
}

public void launchCommand(String inputDir, String outputDir) {
    String command = ".\\venv\\Scripts\\python.exe ./test.py -i " + inputDir + " -o " + outputDir;
    String output = this.executeCommand(command);
    System.out.println(output);
}

The problem is the script is launch by the javafx graphical thread so the line

p.waitFor();

will lock the javafx thread and so my gui stops responding...

I dont know how solve this problem... Thank you in advance for your help !

Upvotes: 1

Views: 1492

Answers (1)

James_D
James_D

Reputation: 209418

Just run the script in a background thread, and make sure you update the GUI back on the FX Application Thread, either using Platform.runLater(...) or by encapsulating the command as a Task and using the setOnSucceeded handler. The best practice here is to use an ExecutorService to manage the threads.

For example:

private final ExecutorService exec = Executors.newCachedThreadPool();

public void launchCommand(String inputDir, String outputDir) {
    String command = ".\\venv\\Scripts\\python.exe ./test.py -i " + inputDir + " -o " + outputDir;
    Task<String> commandTask = new Task<String>() {
        @Override
        protected String call() {
            return executeCommand(command);
        }
    };
    commandTask.setOnSucceeded(event -> {
        // this is executed on the FX Application Thread, 
        // so it is safe to update the UI here if you need
        System.out.println(commandTask.getValue());
    });
    commandTask.setOnFailed(event -> {
        commandTask.getException().printStackTrace();
    });
    exec.execute(commandTask);

}

Upvotes: 2

Related Questions