JavaFX | Redirect console output to TextArea

In this tutorial, you will learn to redirect console output to textarea in JavaFX application. This is a very useful implementation for most of the applications. I have explained the whole implementation step by step with the help of a diagram.

See the below diagram, this is showing the core logic to redirect console output to the text area.
Basically, I have created a new PrintStream object with the help of PipedOutputStream and PipedInputstream and then associated it with the Out object of the system class. After that, a reader thread is created and executed as a daemon thread to read the input stream from pipedoutputstream and convert this byte stream to text then write inside JavaFX TextArea.
Please watch the below video tutorial for a better understanding.

Source code download link for the files used in the demo project:

1) FXMLDocument.fxml

 <?xml version=”1.0″ encoding=”UTF-8″?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id=”AnchorPane” fx:id=”myAnchorPane” prefHeight=”367.0″ prefWidth=”467.0″ xmlns=”http://javafx.com/javafx/8″ xmlns:fx=”http://javafx.com/fxml/1″ fx:controller=”javafxconsoletextarea.FXMLDocumentController”>
    <children>
        <Button fx:id=”button” layoutX=”142.0″ layoutY=”87.0″ onAction=”#handleButtonAction” text=”Click to execute something” />
        <Label fx:id=”label” layoutX=”11.0″ layoutY=”127.0″ minHeight=”16″ minWidth=”69″ text=”Console Output”>
         <font>
            <Font name=”System Bold” size=”12.0″ />
         </font></Label>
      <TextArea fx:id=”textAreaUI” editable=”false” layoutX=”11.0″ layoutY=”147.0″ prefHeight=”206.0″ prefWidth=”443.0″ />
      <Pane layoutX=”2.0″ layoutY=”3.0″ prefHeight=”39.0″ prefWidth=”460.0″ style=”-fx-background-color: blue;”>
         <children>
            <Label layoutX=”14.0″ layoutY=”5.0″ prefHeight=”27.0″ prefWidth=”344.0″ text=”Redirecting Console output to TextArea” textFill=”#fffefe”>
               <font>
                  <Font name=”System Bold Italic” size=”18.0″ />
               </font>
            </Label>
         </children>
      </Pane>
    </children>
</AnchorPane>

2)FXMLDocumentController.java

package javafxconsoletextarea;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextArea;
public class FXMLDocumentController implements Initializable {
    @FXML
    private TextArea textAreaUI;
    static TextArea staticTxtArea;
    @FXML
    private void handleButtonAction(ActionEvent event) {
        // these will be redirected to textArea on GUI
        System.err.println(“@@@@ERROR: This is error”);
        System.out.println(“####OUTPUT : THIS IS ERROR”);
        //generating an exception to print on console
        try
        {
          int x  = 5/0;
        }
        catch(Exception ex)
        {
          ex.printStackTrace();
         // System.out.println(ex.getMessage());
        }
    }
    @Override
    public void initialize(URL url, ResourceBundle rb) {
       staticTxtArea = textAreaUI;
  }
}

3) JavaFXConsoleTextArea.java

package javafxconsoletextarea;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class JavaFXConsoleTextArea extends Application {
    private final PipedInputStream pipeIn = new PipedInputStream();
    private final PipedInputStream pipeIn2 = new PipedInputStream();
    Thread errorThrower;
    private Thread reader;
    private Thread reader2;
    boolean quit;
    private TextArea txtArea;
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource(“FXMLDocument.fxml”));
        //Console myConsole = new Console();
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
        txtArea = FXMLDocumentController.staticTxtArea;
        //Thread execution for reading output stream
        executeReaderThreads();
        //Thread closing on stag close event
        stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
        @Override
        public void handle(WindowEvent e) {
        closeThread();
        Platform.exit();
        System.exit(0);
        }
        });
    }
    //method to handle thread closing on stage closing
    synchronized void closeThread()
    {
       System.out.println(“Message: Stage is closed.”);
       this.quit = true;
       notifyAll();
       try { this.reader.join(1000L); this.pipeIn.close(); } catch (Exception e) {
       }try { this.reader2.join(1000L); this.pipeIn2.close(); } catch (Exception e) {
       }System.exit(0);
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
    public void executeReaderThreads()
    {
      try
      {
      PipedOutputStream pout = new PipedOutputStream(this.pipeIn);
      System.setOut(new PrintStream(pout, true));
      }
      catch (IOException io)
      { }
      catch (SecurityException se)
      { }
    try
    {
      PipedOutputStream pout2 = new PipedOutputStream(this.pipeIn2);
      System.setErr(new PrintStream(pout2, true));
    }
    catch (IOException io)
    {
    }
    catch (SecurityException se)
    {
    }
ReaderThread obj = new ReaderThread(pipeIn, pipeIn2, errorThrower, reader, reader2, quit, txtArea);
    }
}

4) ReaderThread.java

 
package javafxconsoletextarea;
import java.io.IOException;
import java.io.PipedInputStream;
import javafx.scene.control.TextArea;
public class ReaderThread implements Runnable{
    private final PipedInputStream pipeIn ;
    private final PipedInputStream pipeIn2 ;
    Thread errorThrower;
    private Thread reader;
    private Thread reader2;
    private boolean quit;
    private TextArea txtArea;
    ReaderThread(PipedInputStream pinInput1, PipedInputStream pinInput2, Thread errorThrower1, Thread reader11, Thread reader22, boolean newflag, TextArea txtArea1)
    {
       pipeIn = pinInput1;
       pipeIn2 = pinInput2;
       errorThrower = errorThrower1;
       reader = reader11;
       reader2 = reader22;
       quit =  newflag;
       txtArea = txtArea1;
    this.quit = false;
    this.reader = new Thread(this);
    this.reader.setDaemon(true);
    this.reader.start();
    this.reader2 = new Thread(this);
    this.reader2.setDaemon(true);
    this.reader2.start();
    this.errorThrower = new Thread(this);
    this.errorThrower.setDaemon(true);
    this.errorThrower.start();
    }
  public synchronized void run()
  {
    try
    {
      while (Thread.currentThread() == this.reader) {
        try {
             wait(100L);
        }
        catch (InterruptedException ie)
        {
            System.out.println(“I am in thread 1”);
        }
        if (this.pipeIn.available() != 0)
        {
          String input = readLine(this.pipeIn); //reading console output stream from pipedinputstream
          this.txtArea.appendText(input);
        }
        if (this.quit) return;
      }
      //while loop starting
      while (Thread.currentThread() == this.reader2) {
        try {
          wait(100L);
        }
        catch (InterruptedException ie)
        {
        }
        if (this.pipeIn2.available() != 0)
        {
          String input = readLine(this.pipeIn2);
           this.txtArea.appendText(input);
        }
        if (this.quit) return; //if some one closed the stage then this check will be performed every time, if true
        //thread execution will be stopped.
      } //while loop ending here
    }
    catch (Exception e)
    {
    }
    if (Thread.currentThread() == this.errorThrower) {
      try {
        wait(800L);
      }
      catch (InterruptedException ie) {
      }
      System.out.println(“****************************Console Started Successfully********************************************************”);
    }
  }
  public synchronized String readLine(PipedInputStream in)
    throws IOException
  {
    String input = “”;
    do
    {
      int available = in.available();
      if (available == 0) break;
      byte[] b = new byte[available];
      in.read(b);
      input = input + new String(b, 0, b.length);
    }while ((!input.endsWith(“n”)) && (!input.endsWith(“rn”)) && (!this.quit));
    return input;
  }
}
If you have any doubts so please ask in comment box below on this post. I will try my best to reply as soon as possible.
Happy Coding Guys.  🙂

3 thoughts on “JavaFX | Redirect console output to TextArea”

  1. Thank you very much for this information. But i have a requirement of displaying this console text area fields in multiple tabs. Whichever the tab i visit and do some action based on that i need to display console output in the corresponding tab.any suggestions would be helpful

    Reply
  2. Hi, I copied your code and run main from JavaFXConsoleTextArea.java. I'm getting the following error. Any help would greatly be appreciated. Thanks.
    Exception in Application start method
    java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:465)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
    Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
    at java.base/java.lang.Thread.run(Thread.java:829)
    Caused by: java.lang.IllegalStateException: Location is not set.
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2541)
    at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2516)
    at com.example.consoletotextarea/javafxconsoletextarea.JavaFXConsoleTextArea.start(JavaFXConsoleTextArea.java:34)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
    … 1 more
    Exception running application javafxconsoletextarea.JavaFXConsoleTextArea

    JavaFXConsoleTextArea.java:34 is referring to line Scene scene = new Scene(fxmlLoader.load());

    Reply

Leave a Comment