6

编辑:我已经编辑了帖子以澄清我的问题,现在我自己有了更多的理解。

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

这是我目前正在做的事情:

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()will 正如它在文档中所说的那样:

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

所以我真正想做的是run()在处理 EventQueue 中的所有其他内容之前执行我对 GUI 的更新(调用)。

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

谢谢,

4

5 回答 5

11

以下示例创建带有文本区域的框架并将 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);
        }
    }
}
于 2013-02-05T11:52:57.800 回答
5

您的错误必须存在于您尚未向我们展示的其他地方。这是一个非常简单的演示,它使用与您的代码几乎相同的代码按预期工作(我只修复了小问题):

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();
            }
        });
    }
}
于 2013-02-05T15:22:13.883 回答
3

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

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

于 2013-02-05T11:46:52.110 回答
1

我发现做到这一点的最好方法非常简单,而且看起来效果很好。我已经用了很多年了,没有任何问题。

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");
于 2018-05-27T09:13:10.683 回答
0

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

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());
于 2016-04-11T14:05:24.510 回答