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.
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. 🙂
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
Hi , i want to use this code and redirect to a file
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());