如何将输出流设置为TextArea

我正在尝试为程序创建GUI面板,我想要通常打印到我的命令提示符的所有内容,以打印到TextArea对象。 我的GUI面板大部分都是格式化的,我无法将文本打印到TextArea,这里是我的文件:

package guipanel; import javax.swing.*; import java.awt.*; import java.io.*; /** * * @author Dan */ public class GUIPanel extends JFrame { public GUIPanel() { initComponents(); } private void setOutputStream(boolean catchErrors) { System.setOut(aPrintStream); setVisible(true); requestFocus(); if (catchErrors) { System.setErr(aPrintStream); } } private void addTabs(JTabbedPane jTabbedPane1) { JPanel jPanel1 = new JPanel(); JPanel jPanel2 = new JPanel(); JPanel jPanel3 = new JPanel(); JPanel jPanel4 = new JPanel(); jTabbedPane1.add("Main", textArea1); jTabbedPane1.add("Commands", jPanel); jTabbedPane1.add("Rules", jPanel1); jTabbedPane1.add("Links", jPanel2); jTabbedPane1.add("Information", jPanel3); jTabbedPane1.add("Shutdown", jPanel4); setOutputStream(true); } @SuppressWarnings("unchecked") private void initComponents() { textArea1 = new java.awt.TextArea(); jTabbedPane1 = new javax.swing.JTabbedPane(); jMenuBar1 = new javax.swing.JMenuBar(); jMenu1 = new javax.swing.JMenu(); jMenu2 = new javax.swing.JMenu(); textArea1.setPreferredSize(new java.awt.Dimension(432, 343)); textArea1.getAccessibleContext().setAccessibleParent(jTabbedPane1); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("Evolution-X 639"); setBounds(new java.awt.Rectangle(0, 0, 400, 450)); setResizable(false); getContentPane().setLayout(new java.awt.FlowLayout()); addTabs(jTabbedPane1); getContentPane().add(jTabbedPane1); jMenu1.setText("File"); jMenuBar1.add(jMenu1); jMenu2.setText("Edit"); jMenuBar1.add(jMenu2); setJMenuBar(jMenuBar1); pack(); } public static void main(String args[]) { try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (InstantiationException ex) { java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new GUIPanel().setVisible(true); } }); } private JMenu jMenu1; private JMenu jMenu2; private JMenuBar jMenuBar1; private JTabbedPane jTabbedPane1; private TextArea textArea1; private JPanel jPanel = new JPanel(); private PrintStream aPrintStream = new PrintStream( new FilterOutputStream( new ByteArrayOutputStream())); } 

您需要将打印流重定向到您可以控制的输出流…

这是我为正在努力工作的应用程序开发的概念示例。 我们使用它来在用户站点运行时调出输出控制台,这样我们就可以看到发送到标准输出的内容……直到我们修复了我们的日志记录;)

基本上它将自定义OutputStream放在打印流和控制台之间以捕获输出,但仍允许将内容打印到控制台。 如果您从命令行或IDE运行该程序,这将非常有用。 如果你想要的话,你可以设置一个开关来阻止它……

在此处输入图像描述

 public class TestRedirect { public static void main(String[] args) { new TestRedirect(); } public TestRedirect() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException ex) { } catch (InstantiationException ex) { } catch (IllegalAccessException ex) { } catch (UnsupportedLookAndFeelException ex) { } CapturePane capturePane = new CapturePane(); JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(capturePane); frame.setSize(200, 200); frame.setLocationRelativeTo(null); frame.setVisible(true); PrintStream ps = System.out; System.setOut(new PrintStream(new StreamCapturer("STDOUT", capturePane, ps))); System.out.println("Hello, this is a test"); System.out.println("Wave if you can see me"); } }); } public class CapturePane extends JPanel implements Consumer { private JTextArea output; public CapturePane() { setLayout(new BorderLayout()); output = new JTextArea(); add(new JScrollPane(output)); } @Override public void appendText(final String text) { if (EventQueue.isDispatchThread()) { output.append(text); output.setCaretPosition(output.getText().length()); } else { EventQueue.invokeLater(new Runnable() { @Override public void run() { appendText(text); } }); } } } public interface Consumer { public void appendText(String text); } public class StreamCapturer extends OutputStream { private StringBuilder buffer; private String prefix; private Consumer consumer; private PrintStream old; public StreamCapturer(String prefix, Consumer consumer, PrintStream old) { this.prefix = prefix; buffer = new StringBuilder(128); buffer.append("[").append(prefix).append("] "); this.old = old; this.consumer = consumer; } @Override public void write(int b) throws IOException { char c = (char) b; String value = Character.toString(c); buffer.append(value); if (value.equals("\n")) { consumer.appendText(buffer.toString()); buffer.delete(0, buffer.length()); buffer.append("[").append(prefix).append("] "); } old.print(c); } } } 

在此处输入图像描述在此处输入图像描述

更新了工作示例。 在Windows 7,Java 6和Mac OS Lion Java 7上进行测试

MadProgrammer的解决方案非常棒,我的基础是我的。 但是,正如Loopkin所指出的,它不处理特殊字符(准确地说,它在每个非ASCII字符上都失败了)。

Loopkin的解决方案对我不起作用,但我终于提出了两个完成这项工作的解决方案。

解决方案1:处理每1个字节的字符(最多U + 00FF)

这个简单的解决方案可以处理U + 00FF(每个1字节字符)的每个字符。 一切都与MadProgrammer完全相同,但write()定义如下:

 @Override public void write(int b) throws IOException { buffer.append(Character.toChars((b + 256) % 256)); if ((char) b == '\n') { textArea.append(str); textArea.setCaretPosition(textArea.getDocument().getLength()); buffer.delete(0, buffer.length()); } old.write(b); } 

我没有把前缀的东西,因为我不需要它。

解决方案2:处理每个对象,如标准输出

最后,我决定包含所有字符,所以我最终直接扩展PrintStream ,并将前缀/缩进放回去。 问题是我无法覆盖私有方法write(String s) ,所以我覆盖了所有的print()方法:

 public class PrintStreamCapturer extends PrintStream { private JTextArea text; private boolean atLineStart; private String indent; public PrintStreamCapturer(JTextArea textArea, PrintStream capturedStream, String indent) { super(capturedStream); this.text = textArea; this.indent = indent; this.atLineStart = true; } public PrintStreamCapturer(JTextArea textArea, PrintStream capturedStream) { this(textArea, capturedStream, ""); } private void writeToTextArea(String str) { if (text != null) { synchronized (text) { text.setCaretPosition(text.getDocument().getLength()); text.append(str); } } } private void write(String str) { String[] s = str.split("\n", -1); if (s.length == 0) return; for (int i = 0; i < s.length - 1; i++) { writeWithPotentialIndent(s[i]); writeWithPotentialIndent("\n"); atLineStart = true; } String last = s[s.length - 1]; if (!last.equals("")) { writeWithPotentialIndent(last); } } private void writeWithPotentialIndent(String s) { if (atLineStart) { writeToTextArea(indent + s); atLineStart = false; } else { writeToTextArea(s); } } private void newLine() { write("\n"); } @Override public void print(boolean b) { synchronized (this) { super.print(b); write(String.valueOf(b)); } } @Override public void print(char c) { synchronized (this) { super.print(c); write(String.valueOf(c)); } } @Override public void print(char[] s) { synchronized (this) { super.print(s); write(String.valueOf(s)); } } @Override public void print(double d) { synchronized (this) { super.print(d); write(String.valueOf(d)); } } @Override public void print(float f) { synchronized (this) { super.print(f); write(String.valueOf(f)); } } @Override public void print(int i) { synchronized (this) { super.print(i); write(String.valueOf(i)); } } @Override public void print(long l) { synchronized (this) { super.print(l); write(String.valueOf(l)); } } @Override public void print(Object o) { synchronized (this) { super.print(o); write(String.valueOf(o)); } } @Override public void print(String s) { synchronized (this) { super.print(s); if (s == null) { write("null"); } else { write(s); } } } @Override public void println() { synchronized (this) { newLine(); super.println(); } } @Override public void println(boolean x) { synchronized (this) { print(x); newLine(); super.println(); } } @Override public void println(char x) { synchronized (this) { print(x); newLine(); super.println(); } } @Override public void println(int x) { synchronized (this) { print(x); newLine(); super.println(); } } @Override public void println(long x) { synchronized (this) { print(x); newLine(); super.println(); } } @Override public void println(float x) { synchronized (this) { print(x); newLine(); super.println(); } } @Override public void println(double x) { synchronized (this) { print(x); newLine(); super.println(); } } @Override public void println(char x[]) { synchronized (this) { print(x); newLine(); super.println(); } } @Override public void println(String x) { synchronized (this) { print(x); newLine(); super.println(); } } @Override public void println(Object x) { String s = String.valueOf(x); synchronized (this) { print(s); newLine(); super.println(); } } } 

我删除了Consumer方面以保持简单,但实际需要的一切都在这里。 以下是我使用这个类的方法:

 System.setOut(new PrintStreamCapturer(logTextArea, System.out)); System.setErr(new PrintStreamCapturer(logTextArea, System.err, "[ERROR] ")); 

我喜欢MadProgrammer的答案,但我认为这不适用于UTF-8字符。

相反,我会使StreamCapturer扩展ByteArrayOutputStream并将其用作写入实现。

  @Override public void write(int b){ if ('\n' == (char) b) { consumer.appendText(toString()); reset(); } else { super.write(b); } old.write(b); } 

我正在跳过前缀部分,因为我在实现中不需要它。 感谢您的代码,它给了我很大的帮助!

只是更新原始MadProgrammer的NOOBS代码 – 将JTextArea参数传递给构造函数,例如

 new RedirectText(Main.window.textArea1);