How to set output stream to TextArea

36,003

Solution 1

You need to redirect the print stream to an output stream you can control...

This is an example of concept I developed for an application I'm working on for work. We use this to bring up the output console when it's running at user sites so we can see what's being sent to standard out...until we fixed our logging that is ;)

Basically it puts a custom OutputStream in between the print stream and the console to capture the output, but still allows the content to printed to the console. This is helpful if you're running the program from the command line or IDE. You could put a switch to stop this if you wanted...

enter image description here

public class TestRedirect {

    public static void main(String[] args) {
        new TestRedirect();
    }

    public TestRedirect() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                CapturePane capturePane = new CapturePane();
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(capturePane);
                frame.setSize(200, 200);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                PrintStream ps = System.out;
                System.setOut(new PrintStream(new StreamCapturer("STDOUT", capturePane, ps)));

                System.out.println("Hello, this is a test");
                System.out.println("Wave if you can see me");
            }            
        });
    }

    public class CapturePane extends JPanel implements Consumer {

        private JTextArea output;

        public CapturePane() {
            setLayout(new BorderLayout());
            output = new JTextArea();
            add(new JScrollPane(output));
        }

        @Override
        public void appendText(final String text) {
            if (EventQueue.isDispatchThread()) {
                output.append(text);
                output.setCaretPosition(output.getText().length());
            } else {

                EventQueue.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        appendText(text);
                    }
                });

            }
        }        
    }

    public interface Consumer {        
        public void appendText(String text);        
    }

    public class StreamCapturer extends OutputStream {

        private StringBuilder buffer;
        private String prefix;
        private Consumer consumer;
        private PrintStream old;

        public StreamCapturer(String prefix, Consumer consumer, PrintStream old) {
            this.prefix = prefix;
            buffer = new StringBuilder(128);
            buffer.append("[").append(prefix).append("] ");
            this.old = old;
            this.consumer = consumer;
        }

        @Override
        public void write(int b) throws IOException {
            char c = (char) b;
            String value = Character.toString(c);
            buffer.append(value);
            if (value.equals("\n")) {
                consumer.appendText(buffer.toString());
                buffer.delete(0, buffer.length());
                buffer.append("[").append(prefix).append("] ");
            }
            old.print(c);
        }        
    }    
}

enter image description here enter image description here

Updated with working example. Test on Windows 7, Java 6 and Mac OS Lion Java 7

Solution 2

MadProgrammer's solution is really great, and I based mine upon his. However, as pointed out by Loopkin, it does not deal with special characters (to be accurate, it fails on every non-ASCII character).

Loopkin's solution did not work for me, but I finally came up with 2 solutions that did the job.

Solution 1: handles every 1 byte character (up to U+00FF)

This simple solution handles every character up to U+00FF (every 1-byte character). Everything is identical as MadProgrammer, except write() which is defined as:

@Override
public void write(int b) throws IOException {
    buffer.append(Character.toChars((b + 256) % 256));
    if ((char) b == '\n') {
        textArea.append(str);
        textArea.setCaretPosition(textArea.getDocument().getLength());
        buffer.delete(0, buffer.length());
    }
    old.write(b);
}

I haven't put the prefix stuff, because I did not need it.

Solution 2: handles every Object like standard output

In the end, I decided to include all the characters so I ended up extending directly PrintStream, and also put the prefix/indent back. The problem is I couldn't override the private method write(String s), so I overrode all the print() methods:

public class PrintStreamCapturer extends PrintStream {

    private JTextArea text;
    private boolean atLineStart;
    private String indent;

    public PrintStreamCapturer(JTextArea textArea, PrintStream capturedStream, String indent) {
        super(capturedStream);
        this.text = textArea;
        this.indent = indent;
        this.atLineStart = true;
    }

    public PrintStreamCapturer(JTextArea textArea, PrintStream capturedStream) {
        this(textArea, capturedStream, "");
    }

    private void writeToTextArea(String str) {
        if (text != null) {
            synchronized (text) {
                text.setCaretPosition(text.getDocument().getLength());
                text.append(str);
            }
        }
    }

    private void write(String str) {
        String[] s = str.split("\n", -1);
        if (s.length == 0)
            return;
        for (int i = 0; i < s.length - 1; i++) {
            writeWithPotentialIndent(s[i]);
            writeWithPotentialIndent("\n");
            atLineStart = true;
        }
        String last = s[s.length - 1];
        if (!last.equals("")) {
            writeWithPotentialIndent(last);
        }
    }

    private void writeWithPotentialIndent(String s) {
        if (atLineStart) {
            writeToTextArea(indent + s);
            atLineStart = false;
        } else {
            writeToTextArea(s);
        }
    }

    private void newLine() {
        write("\n");
    }

    @Override
    public void print(boolean b) {
        synchronized (this) {
            super.print(b);
            write(String.valueOf(b));
        }
    }

    @Override
    public void print(char c) {
        synchronized (this) {
            super.print(c);
            write(String.valueOf(c));
        }
    }

    @Override
    public void print(char[] s) {
        synchronized (this) {
            super.print(s);
            write(String.valueOf(s));
        }
    }

    @Override
    public void print(double d) {
        synchronized (this) {
            super.print(d);
            write(String.valueOf(d));
        }
    }

    @Override
    public void print(float f) {
        synchronized (this) {
            super.print(f);
            write(String.valueOf(f));
        }
    }

    @Override
    public void print(int i) {
        synchronized (this) {
            super.print(i);
            write(String.valueOf(i));
        }
    }

    @Override
    public void print(long l) {
        synchronized (this) {
            super.print(l);
            write(String.valueOf(l));
        }
    }

    @Override
    public void print(Object o) {
        synchronized (this) {
            super.print(o);
            write(String.valueOf(o));
        }
    }

    @Override
    public void print(String s) {
        synchronized (this) {
            super.print(s);
            if (s == null) {
                write("null");
            } else {
                write(s);
            }
        }
    }

    @Override
    public void println() {
        synchronized (this) {
            newLine();
            super.println();
        }
    }

    @Override
    public void println(boolean x) {
        synchronized (this) {
            print(x);
            newLine();
            super.println();
        }
    }

    @Override
    public void println(char x) {
        synchronized (this) {
            print(x);
            newLine();
            super.println();
        }
    }

    @Override
    public void println(int x) {
        synchronized (this) {
            print(x);
            newLine();
            super.println();
        }
    }

    @Override
    public void println(long x) {
        synchronized (this) {
            print(x);
            newLine();
            super.println();
        }
    }

    @Override
    public void println(float x) {
        synchronized (this) {
            print(x);
            newLine();
            super.println();
        }
    }

    @Override
    public void println(double x) {
        synchronized (this) {
            print(x);
            newLine();
            super.println();
        }
    }

    @Override
    public void println(char x[]) {
        synchronized (this) {
            print(x);
            newLine();
            super.println();
        }
    }

    @Override
    public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
            super.println();
        }
    }

    @Override
    public void println(Object x) {
        String s = String.valueOf(x);
        synchronized (this) {
            print(s);
            newLine();
            super.println();
        }
    }
}

I removed the Consumer aspect to keep it simple, but everything that's actually needed is here. Here is how I used this class:

System.setOut(new PrintStreamCapturer(logTextArea, System.out));
System.setErr(new PrintStreamCapturer(logTextArea, System.err, "[ERROR] "));

Solution 3

I like the answer from MadProgrammer but I don't think this would work for UTF-8 chars.

Instead I would make StreamCapturer extend ByteArrayOutputStream and use this as the write implementation.

    @Override
    public void write(int b){
        if ('\n' == (char) b) {
            consumer.appendText(toString());
            reset();
        }
        else {
            super.write(b);
        }
        old.write(b);
    }

I'm skipping the prefix part because I don't need it in my implementation. Thanks for the code though, it's been of great help!

Share:
36,003
Dan
Author by

Dan

Updated on March 16, 2020

Comments

  • Dan
    Dan about 4 years

    I'm trying to create a GUI Panel for a program and I'd like everything, that would normally print to my command prompt, to print to a TextArea object. I have the GUI panel formatted for the most part, I can't get the text to print to the TextArea though, here's my file:

    package guipanel;
    
    import javax.swing.*;
    import java.awt.*;
    import java.io.*;
    
    
    /**
     *
     * @author Dan
     */
    public class GUIPanel extends JFrame { 
        public GUIPanel() {
            initComponents();
        }
        private void setOutputStream(boolean catchErrors) {
            System.setOut(aPrintStream); 
            setVisible(true);
            requestFocus();
            if (catchErrors) {
                   System.setErr(aPrintStream);
            }
        }
        private void addTabs(JTabbedPane jTabbedPane1) {
            JPanel jPanel1 = new JPanel();
            JPanel jPanel2 = new JPanel();
            JPanel jPanel3 = new JPanel();
            JPanel jPanel4 = new JPanel();
            jTabbedPane1.add("Main", textArea1);
            jTabbedPane1.add("Commands", jPanel);
            jTabbedPane1.add("Rules", jPanel1);
            jTabbedPane1.add("Links", jPanel2);
            jTabbedPane1.add("Information", jPanel3);
            jTabbedPane1.add("Shutdown", jPanel4);
            setOutputStream(true);
        }
        @SuppressWarnings("unchecked")
        private void initComponents() {
    
            textArea1 = new java.awt.TextArea();
            jTabbedPane1 = new javax.swing.JTabbedPane();
            jMenuBar1 = new javax.swing.JMenuBar();
            jMenu1 = new javax.swing.JMenu();
            jMenu2 = new javax.swing.JMenu();
    
            textArea1.setPreferredSize(new java.awt.Dimension(432, 343));
            textArea1.getAccessibleContext().setAccessibleParent(jTabbedPane1);
    
            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
            setTitle("Evolution-X 639");
            setBounds(new java.awt.Rectangle(0, 0, 400, 450));
            setResizable(false);
            getContentPane().setLayout(new java.awt.FlowLayout());
    
            addTabs(jTabbedPane1);
            getContentPane().add(jTabbedPane1);
    
            jMenu1.setText("File");
            jMenuBar1.add(jMenu1);
    
            jMenu2.setText("Edit");
            jMenuBar1.add(jMenu2);
    
            setJMenuBar(jMenuBar1);
    
            pack();
        }
        public static void main(String args[]) {
            try {
                for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                    if ("Nimbus".equals(info.getName())) {
                        javax.swing.UIManager.setLookAndFeel(info.getClassName());
                        break;
                    }
                }
            } catch (ClassNotFoundException ex) {
                java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (InstantiationException ex) {
                java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (javax.swing.UnsupportedLookAndFeelException ex) {
                java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            }
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new GUIPanel().setVisible(true);
                }
            });
        }
        private JMenu jMenu1;
        private JMenu jMenu2;
        private JMenuBar jMenuBar1;
        private JTabbedPane jTabbedPane1;
        private TextArea textArea1;
        private JPanel jPanel = new JPanel();
        private PrintStream aPrintStream  =
           new PrintStream(
             new FilterOutputStream(
               new ByteArrayOutputStream()));
    }
    
  • MadProgrammer
    MadProgrammer over 11 years
    Thanks for the heads up, I've correct the bug and tested it on Windows (Java 6 & 7) and Mac OS Lion (Java 7)
  • MadProgrammer
    MadProgrammer over 11 years
    Sorry about the bug, trying to be smart :P
  • Muhammad Bilal Hasan
    Muhammad Bilal Hasan about 9 years
    What about showing the console output during runtime? Can you refer any example?
  • MadProgrammer
    MadProgrammer about 9 years
    @BilalHasan This will output anything the program outputs to the stdout. What are you trying to do?
  • Muhammad Bilal Hasan
    Muhammad Bilal Hasan about 9 years
    hi, I have figuer out how to show the System.out.println("console print"); on text area but I'm facing one problem. I have a function which is the main working in my application. It scraps the data from some websites and parses them, inside this method I have several console outputs. Now the problem is if I try to print the console output (just for test) without calling this method the textarea shows every test print. But if I call this method and test the prints, then I see the blank text area. Help required please.
  • Hunter Tran
    Hunter Tran over 4 years
    I created a Github repository to demonstrate this solution here: github.com/huntertran/javaswing-multiple-ouput.git
  • MadProgrammer
    MadProgrammer almost 3 years
    You could just change the font of the JTextArea