1

I have a batch file which is supposed to be started from my JavaFX application.

I have tried different implementations:

Append the output of the program in a file, then after the process finishes, read the file, and append the content to my TextBox.

This is wrong for many reasons, and mainly, because the GUI hangs, until the program finishes.

So I looked into using threads, but when using while(process.isAlive()) in a thread, the same thing happens. I tried to do it so while the process is running, add contents of the output to my textBox. It only gets added after the program finished, even if I do this in a separate thread.

I have also bee trying to use a Platform.runLater(new Runnable() .... With this, the content gets updated periodically, but still in big chunks of data at a time, and also makes the GUI hang.

Then I've found that JavaFX is not thread-safe, and that there is a library:

javafx.concurrent.Task

There is an example for it here: https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm

But still, I'm not sure if I am getting closer to what I am looking for...

Basically, I need something like this, but which makes the GUI not hang:

        Process p = Runtime.getRuntime().exec(executeString);
        InputStream is = p.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        while(p.isAlive())
        {
            String line;
            try
            {
                if ( (line = br.readLine()) != null)
                    logArea.appendText(line + "\n");
            } catch(Exception e)
            {

            }
        }
Wilhelm Sorban
  • 1,012
  • 1
  • 17
  • 37
  • By looking at your code should you not define "Process p" first before "InputStream is = p.getInputStream();" – Joakim Ericsson Mar 25 '16 at 14:03
  • Shouldnt "while(p.isAlive())" also wait for the process to die and then read the file? – Joakim Ericsson Mar 25 '16 at 14:07
  • @JoakimEricsson What file? He's reading from the process. – James_D Mar 25 '16 at 14:14
  • 1
    What is the context for the code you have shown? This should be in the `call` method in the task, and you should update the text area using `Platform.runLater()`. Can you show more of your code, i.e. the `Task` implementation and how you are starting it, etc. – James_D Mar 25 '16 at 14:15
  • @James_D That was it, was almost there. Had to simply put my code in the task constructor. Thanks a lot! – Wilhelm Sorban Mar 25 '16 at 14:22

1 Answers1

-1

The solution was simply to construct a task, like shown in the link, and put the code from my main post into it.

Thanks James_D, your trick did it.

This is the final result:

Task task = new Task<Void>()
        {
            @Override
            public Void call()
            {
                try {
                    Process p = Runtime.getRuntime().exec(executeString);                
                    InputStream is = p.getInputStream();
                    InputStreamReader isr = new InputStreamReader(is);
                    BufferedReader br = new BufferedReader(isr);

                    while(p.isAlive())
                    {
                        String line;
                        if ( (line = br.readLine()) != null)
                            logArea.appendText(line + "\n");
                    }
                } catch (IOException e)
                {
                    e.printStackTrace();
                }
                return null;
            }
        }; 
        new Thread(task).start();

Edit: After reading some more documentations...

http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm

http://docs.oracle.com/javafx/2/api/javafx/concurrent/Task.html

Platform.runLater and Task in JavaFX

The code has been updated to:

                while(p.isAlive())
                {
                    String line;
                    if ((line = br.readLine()) != null)
                    {
                        Platform.runLater(new Runnable() 
                        {
                            @Override
                            public void run()
                            {
                                logArea.appendText(line + "\n");
                            }
                        });
                    }
                }
Community
  • 1
  • 1
Wilhelm Sorban
  • 1,012
  • 1
  • 17
  • 37
  • 1
    Hmm. While this may appear to work, you are violating JavaFX's single threaded rule. You need to invoke `logArea.appendText(...)` on the FX Application Thread: `Platform.runLater(() -> logArea.appendText(...));`. – James_D Mar 25 '16 at 14:35