From: Erik on
The following code is meant to redirect text from System.out to a
JTextArea. However, it does not make each output visible immediately:
it sort of buffers. How can I change it, so it shows eacht line
immediately after an "System.out.println(...); ?

======================================
private void updateTextArea(final String text) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textArea.append(text); // it will append, but not show
immediately ...
}
});
}

private void redirectSystemStreams() {
OutputStream out = new OutputStream() {
@Override
public void write(int b) throws IOException {
updateTextArea(String.valueOf((char) b));
}

@Override
public void write(byte[] b, int off, int len) throws IOException
{
updateTextArea(new String(b, off, len));
}

@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
};

System.setOut(new PrintStream(out, true));
System.setErr(new PrintStream(out, true));
}
From: Mayeul on
Erik wrote:
> ======================================
> private void updateTextArea(final String text) {
> SwingUtilities.invokeLater(new Runnable() {
> public void run() {
> textArea.append(text); // it will append, but not show
> immediately ...
> }
> });
> }

You might want to replace invokeLater() with invokeAndWait().

I usually think this use case does not look immediate with
invokeLater(), but does with invokeAndWait().

--
Mayeul
From: Erik on
On Thu, 21 Jan 2010 14:16:02 +0100, Mayeul <mayeul.marguet(a)free.fr>
wrote:

>Erik wrote:
>> ======================================
>> private void updateTextArea(final String text) {
>> SwingUtilities.invokeLater(new Runnable() {
>> public void run() {
>> textArea.append(text); // it will append, but not show
>> immediately ...
>> }
>> });
>> }
>
>You might want to replace invokeLater() with invokeAndWait().
>
>I usually think this use case does not look immediate with
>invokeLater(), but does with invokeAndWait().


I get:

Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call
invokeAndWait from the event dispatcher thread
at java.awt.EventQueue.invokeAndWait(EventQueue.java:980)
From: John B. Matthews on
In article <51egl512ho3p9te0158rpr9tcuhqonl4j0(a)4ax.com>,
Erik <et57(a)hotmail.com> wrote:

> The following code is meant to redirect text from System.out to a
> JTextArea. However, it does not make each output visible immediately:
> it sort of buffers. How can I change it, so it shows eacht line
> immediately after an "System.out.println(...); ?
>
> private void updateTextArea(final String text) {
> SwingUtilities.invokeLater(new Runnable() {
> public void run() {
> textArea.append(text); // it will append, but not show immediately ...
> }
> });
> }

Why? The append() method is thread safe.

<http://java.sun.com/javase/6/docs/api/javax/swing/JTextArea.html#append(java.lang.String)>

--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>
From: Peter Duniho on
Erik wrote:
> On Thu, 21 Jan 2010 14:16:02 +0100, Mayeul <mayeul.marguet(a)free.fr>
> wrote:
>
>> [...]
>> You might want to replace invokeLater() with invokeAndWait().
>>
>> I usually think this use case does not look immediate with
>> invokeLater(), but does with invokeAndWait().
>
> I get:
>
> Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call
> invokeAndWait from the event dispatcher thread
> at java.awt.EventQueue.invokeAndWait(EventQueue.java:980)

As John says, since the JTextArea.append() method is thread-safe, why
bother with the "invoke" method at all? But on top of that, if your
code is already executing on the EDT, why are you using either method?

I find it interesting that the exception is thrown. The .NET
equivalents (there are several, depending on what GUI framework one is
using) for "invokeAndWait()" will go ahead and complete the dispatch
directly if the synchronous call is being done on the target thread,
rather than trying to queue the call and then wait for it to complete
(which would of course deadlock in that situation).

But regardless, the Java approach is also a valid design decision, and
it is highlighting the fact that there's something odd about your own
program's implementation.

Now, all that said, I think none of this has answered your original
question, which is why the text does not appear immediately. Without a
SSCCE it's impossible to say for sure what might be the cause of that.
But keep in mind that repainting of Swing components (or AWT for that
matter) does not necessarily happen immediately. The system tracks what
components need redrawing (it's "invalidated"), and then at some
indeterminate time shortly after the invalidation happens, it's actually
redrawn.

Normally, this happens very quickly. Fast enough one wouldn't notice.
But if your program is doing a lot of other stuff, especially on the
EDT, the redrawing may not occur until some time well in the future
(hundreds of milliseconds, or even thousands if you are actively
blocking the EDT with long-running operations). In fact, if there is
some kind of contention going on in the EDT, using "invokeLater()" will
only exacerbate the problem, because it adds an extra trip through the
EDT for the update to the control.

So, the first step here should be for you to figure out what else is
going on in the EDT that is taking so much time and preventing it from
handling the redrawing of your component. No one here can explain it if
you don't post a SSCCE. You'll either have to post one, or figure it
out yourself.

Pete