System.out.println for JTextArea
EDIT: I edited the post to clarify my question, now myself, I have more understanding.
I am essentially, as the title says, trying to pipe the console to mine JTextArea
in my GUI while doing application tasks.
Here's what I'm doing now:
public class TextAreaOutputStream extends OutputStream
{
private final JTextArea textArea;
private final StringBuilder sb = new StringBuilder();
public TextAreaOutputStream(final JTextArea textArea)
{
this.textArea = textArea;
}
@Override
public void flush()
{
}
@Override
public void close()
{
}
@Override
public void write(int b) throws IOException
{
if (b == '\r')
return;
if (b == '\n')
{
final String text = sb.toString() + "\n";
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
textArea.append(text);
}
});
sb.setLength(0);
}
sb.append((char) b);
}
}
The above will successfully redirect System.out
to my above output stream and hence dispatch an event in EventQueue
to update my GUI ( JTextArea
).
Here's the problem:
The current usage invokeLater()
would be, as the docs say:
Causes runnable to have its run method called in the dispatch thread of the EventQueue. This will happen after all pending events are processed.
So what I really want to do is perform my update in the GUI (call run()
) before handling everything else in the EventQueue.
Is it possible to inject an event into my EventQueue? Or can anyone point me to a decent tutorial on this area?
thank,
source to share
The following example creates a frame with a text area and redirects to System.out:
import java.awt.BorderLayout;
import java.awt.Container;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class JTextAreaOutputStream extends OutputStream
{
private final JTextArea destination;
public JTextAreaOutputStream (JTextArea destination)
{
if (destination == null)
throw new IllegalArgumentException ("Destination is null");
this.destination = destination;
}
@Override
public void write(byte[] buffer, int offset, int length) throws IOException
{
final String text = new String (buffer, offset, length);
SwingUtilities.invokeLater(new Runnable ()
{
@Override
public void run()
{
destination.append (text);
}
});
}
@Override
public void write(int b) throws IOException
{
write (new byte [] {(byte)b}, 0, 1);
}
public static void main (String[] args) throws Exception
{
JTextArea textArea = new JTextArea (25, 80);
textArea.setEditable (false);
JFrame frame = new JFrame ("stdout");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane ();
contentPane.setLayout (new BorderLayout ());
contentPane.add (
new JScrollPane (
textArea,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED),
BorderLayout.CENTER);
frame.pack ();
frame.setVisible (true);
JTextAreaOutputStream out = new JTextAreaOutputStream (textArea);
System.setOut (new PrintStream (out));
while (true)
{
System.out.println ("Current time: " + System.currentTimeMillis ());
Thread.sleep (1000L);
}
}
}
source to share
Your mistake must lie elsewhere, which you haven't shown us yet. Here's a very simple demo that works as expected with almost the same code as yours (I've been fixing minor issues):
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TextAreaOutputStream extends OutputStream {
private final JTextArea textArea;
private final StringBuilder sb = new StringBuilder();
public TextAreaOutputStream(final JTextArea textArea) {
this.textArea = textArea;
}
@Override
public void flush() {
}
@Override
public void close() {
}
@Override
public void write(int b) throws IOException {
if (b == '\r') {
return;
}
if (b == '\n') {
final String text = sb.toString() + "\n";
textArea.append(text);
sb.setLength(0);
} else {
sb.append((char) b);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame(TextAreaOutputStream.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea ta = new JTextArea(24, 80);
System.setOut(new PrintStream(new TextAreaOutputStream(ta)));
frame.add(new JScrollPane(ta));
frame.pack();
frame.setVisible(true);
System.out.println("Textarea console initiated");
Timer t = new Timer(1000, new ActionListener() {
int count = 1;
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Outputting line " + count++ + " to the console. Working properly, no?");
}
});
t.start();
}
});
}
}
source to share
You may need to use PipedOutputStream
... see the answers to the question here:
How to redirect all console output to a Swing JTextArea / JTextPane with the correct encoding?
Basically what it is, it redirects System.out
to a buffer from which the program can read the output printed with System.out
. It is calledPiping
source to share
If you want to see the scrolling effect in the text area, then instead of adding output, you can put the new text at the beginning. Example:
HttpURLConnection con = (HttpURLConnection) (new URL(url[0]).openConnection());
con.setInstanceFollowRedirects(false);
con.connect();
int responseCode = con.getResponseCode();
String location = con.getHeaderField("Location");
textArea.setText(url[0] +"," +responseCode+"," +location+"\n"+textArea.getText()); //new text is prefixed to the existing text
textArea.update(textArea.getGraphics());
source to share