Java System.out.println到JTextArea

Java System.out.println到JTextArea,java,swing,user-interface,jtextarea,Java,Swing,User Interface,Jtextarea,编辑:我编辑了这篇文章来澄清我的问题,现在我自己有了更多的理解 正如标题所说,我基本上是在执行应用程序任务的同时,试图将控制台输出到GUI中的JTextArea 以下是我目前正在做的事情: public class TextAreaOutputStream extends OutputStream { private final JTextArea textArea; private final StringBuilder sb = new StringBuilder();

编辑:我编辑了这篇文章来澄清我的问题,现在我自己有了更多的理解

正如标题所说,我基本上是在执行应用程序任务的同时,试图将控制台输出到GUI中的
JTextArea

以下是我目前正在做的事情:

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);
    }
}
上述操作将成功地将
System.out
重新定向到上面的我的输出流,从而将事件发送到
事件队列
,以更新我的GUI(
JTextArea

问题是:

当前使用的
invokeLater()
将如文档中所述:

使runnable在EventQueue的调度线程中调用其run方法。这将在处理所有未决事件后发生。

因此,我实际上想做的是在处理EventQueue中的所有其他内容之前,对GUI执行更新(调用
run()

是否可以将事件本质上注入到我的EventQueue中?或者有人能给我指一本关于这个领域的不错的教程吗


谢谢,

您可能需要使用
PipedOutputStream
。。。请参见以下问题的答案:


基本上,它将
System.out
重定向到一个缓冲区,程序可以从中读取用
System.out
打印的输出。这被称为
管道

以下示例创建带有文本区域的框架,并将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);
        }
    }
}

你的错误一定在别的地方,你还没有告诉我们。这是一个非常简单的演示,它的代码与您的代码几乎相同(我只修复了一些小问题):


如果您想在文本区域中看到滚动效果,则可以将新文本放在开头,而不是附加输出。 例如:


我发现最好的方法是非常简单,而且似乎效果很好。我已经用了很多年了,没有任何问题

JTextArea output = new JTextArea();
PrintStream out = new PrintStream(new OutputStream() {
@Override
    public void write(int b) throws IOException {
        output.append(""+(char)(b & 0xFF));
    }
});
System.setOut(out);
System.out.println("TEST");

嗯,我的方法有什么问题?我在这里看到的是你刚刚重新创建了我的解决方案?您能指出它在哪里解决了我的问题吗?在上睡觉没有什么错,但应该在EDT上构建GUI组件。您的方法有几个小问题,即每个
'\n'
输出两次,但不会导致您描述的问题。您确定
!“.equals(targetFile.getText())
checkBox.isSelected()
都是真的吗?”上述解决方案的工作原理是,我将sysout带到我的JTextArea,但是当我试图在actionPerformed()中执行此操作时,我没有得到任何输出。“您确定通过了所有这些if吗?”?一个
System.out
调用会起作用,而另一个调用会失败,这是没有充分的理由的。问题是我自己在
invokeLater()
上的愚蠢和误解。我的解决方案正在工作,但不是我所希望的,即,我的GUI在
EventQueue
中的所有其他内容处理完毕后才会更新,这就是我上面代码片段中的
。这不是我想要的。@buymypies顺便说一句,
JTextArea.append
是线程安全的,所以没有必要将它包装在
invokeLater()
中。请查看我对问题的编辑,希望我已经清楚地说明了我要做什么。@buymypies 1)没有必要将
JTextArea.append
包装在
invokeLater()
中。2) 如果您正在考虑对EventQueue上的事件重新排序,请忘记它(这并不难做到):这只意味着您在某个地方有一个错误的设计。如果您需要执行冗长的操作,请不要在EDT上执行,而是使用SwingWorker。
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());
JTextArea output = new JTextArea();
PrintStream out = new PrintStream(new OutputStream() {
@Override
    public void write(int b) throws IOException {
        output.append(""+(char)(b & 0xFF));
    }
});
System.setOut(out);
System.out.println("TEST");