System.out.println to JTextArea



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

正如标题所说,在执行应用程序的任务时,我本质上是在尝试将控制台输出到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重定向到我上面的输出流,并因此向EventQueue发送事件以更新我的GUI(JTextArea)。

问题是:

目前使用invokeLater()将如文档所示:

Causes runnable to have its run method called in the dispatch thread of the EventQueue. This will happen after all pending events are processed.

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

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

谢谢,

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

您的错误一定在您尚未向我们展示的其他地方。这里有一个非常简单的演示,它与您的代码几乎相同(我只修复了一些小问题):

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();
            }
        });
    }
}

您可能需要使用PipedOutputStream。。。请在此处查看问题的答案:如何将所有控制台输出重定向到具有正确编码的Swing JTextArea/JTextPane?

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

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

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");

如果你想在文本区看到滚动效果,那么你可以把新文本放在开头,而不是附加输出。示例:

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());

相关内容

  • 没有找到相关文章