这是一个功能类。您可以使用以下命令将此实例安装到系统中并出错: PrintStream con=new PrintStream(new TextAreaOutputStream(...)); System.setOut(con); System.setErr(con); 2014-02-19 更新:使用 EventQueue.invokeLater() 来避免 GUI 线程问题,这些问题在原始版本中很少出现。 2014-02-27 更新:更好的实施 2014 年 3 月 25 日更新:将文本区域中的行更正记录和删除到 run() 方法中,以避免在控制台充满输出时可能发生的追加和删除之间的竞争条件。最终结果对我来说似乎也更清晰。 更新时间 2022-11-07 :进一步改进实施以完全消除输出泛滥带来的问题。请注意,当输出不堪重负时,此版本将完全抑制输出(使用单行注释)。以前的版本最终会开始 GC 抖动,并且 VM 响应会在很大程度上冻结(实际上并没有崩溃),直到它最终设法赶上。 import java.awt.*; import java.io.*; import java.util.*; import java.util.regex.*; import java.util.List; import javax.swing.*; public class TextAreaOutputStream extends OutputStream { // ************************************************************************************************* // INSTANCE PROPERTIES // ************************************************************************************************* private byte[] oneByte; // array for write(int val); private Appender appender; // most recent action // ************************************************************************************************* // INSTANCE CONSTRUCTORS/INIT/CLOSE/FINALIZE // ************************************************************************************************* public TextAreaOutputStream(JTextArea txtara) { this(txtara,1000); } public TextAreaOutputStream(JTextArea txtara, int maxlin) { this(txtara,maxlin,null); } public TextAreaOutputStream(JTextArea txtara, int maxlin, Pattern rmvptn) { if(maxlin<1) { throw new IllegalArgumentException("TextAreaOutputStream maximum lines must be positive (value="+maxlin+")"); } oneByte=new byte[1]; appender=new Appender(txtara,maxlin,rmvptn); } // ************************************************************************************************* // INSTANCE METHODS - ACCESSORS // ************************************************************************************************* /** Clear the current console text area. */ public synchronized void clear() { if(appender!=null) { appender.clear(); } } // ************************************************************************************************* // INSTANCE METHODS - OUTPUT STREAM IMPLEMENTATION // ************************************************************************************************* public synchronized void close() { appender=null; } public synchronized void flush() { } public synchronized void write(int val) { oneByte[0]=(byte)val; write(oneByte,0,1); } public synchronized void write(byte[] ba) { write(ba,0,ba.length); } public synchronized void write(byte[] ba,int str,int len) { if(appender!=null) { appender.append(bytesToString(ba,str,len)); } } // ************************************************************************************************* // INSTANCE METHODS - UTILITY // ************************************************************************************************* @edu.umd.cs.findbugs.annotations.SuppressWarnings("DM_DEFAULT_ENCODING") static private String bytesToString(byte[] ba, int str, int len) { try { return new String(ba,str,len,"UTF-8"); } catch(UnsupportedEncodingException thr) { return new String(ba,str,len); } // all JVMs are required to support UTF-8 } // ************************************************************************************************* // STATIC NESTED CLASSES // ************************************************************************************************* static class Appender implements Runnable { private final StringBuilder line = new StringBuilder(1000); // current line being assembled private final List<String> lines = new ArrayList<String>(); // lines waiting to be appended private final LinkedList<Integer> lengths = new LinkedList<Integer>(); // lengths of each line within text area private final JTextArea textArea; private final int maxLines; // maximum lines allowed in text area private final Pattern rmvPattern; private boolean clear; private boolean queue; private boolean wrapped; Appender(JTextArea txtara, int maxlin, Pattern rmvptn) { textArea = txtara; maxLines = maxlin; rmvPattern = rmvptn; clear = false; queue = true; wrapped = false; } synchronized void append(String val) { boolean eol = val.endsWith(EOL1) || val.endsWith(EOL2); line.append(val); while(line.length()>LINE_MAX) { emitLine(line.substring(0,LINE_MAX)+EOL1); line.replace(0,LINE_MAX,"[>>] "); } if(eol) { emitLine(line.toString()); line.setLength(0); } } private void emitLine(String lin) { if(lines.size()>10_000) { lines.clear(); lines.add("<console-overflowed>\n"); } else { if(rmvPattern!=null) { lin = rmvPattern.matcher(lin).replaceAll(""); } lines.add(lin); } if(queue) { queue=false; EventQueue.invokeLater(this); } } synchronized void clear() { clear = true; if(queue) { queue = false; EventQueue.invokeLater(this); } wrapped = false; } // MUST BE THE ONLY METHOD THAT TOUCHES textArea! public synchronized void run() { int don = 0; if(clear) { lengths . clear(); lines . clear(); textArea . setText(""); clear = false; } for(String lin: lines) { don += 1; lengths.addLast(lin.length()); if(lengths.size()>=maxLines) { textArea.replaceRange("",0,lengths.removeFirst()); } textArea.append(lin); if(don>=100) { break; } } if(don==lines.size()) { lines.clear(); queue = true; } else { lines.subList(0,don).clear(); EventQueue.invokeLater(this); } } static private final String EOL1 = "\n"; static private final String EOL2 = System.getProperty("line.separator",EOL1); static private final int LINE_MAX = 1000; } 这是它的实际截图: 原文由 Lawrence Dol 发布,翻译遵循 CC BY-SA 4.0 许可协议
这是一个功能类。您可以使用以下命令将此实例安装到系统中并出错:
2014-02-19 更新:使用 EventQueue.invokeLater() 来避免 GUI 线程问题,这些问题在原始版本中很少出现。
2014-02-27 更新:更好的实施
2014 年 3 月 25 日更新:将文本区域中的行更正记录和删除到
run()
方法中,以避免在控制台充满输出时可能发生的追加和删除之间的竞争条件。最终结果对我来说似乎也更清晰。更新时间 2022-11-07 :进一步改进实施以完全消除输出泛滥带来的问题。请注意,当输出不堪重负时,此版本将完全抑制输出(使用单行注释)。以前的版本最终会开始 GC 抖动,并且 VM 响应会在很大程度上冻结(实际上并没有崩溃),直到它最终设法赶上。
这是它的实际截图: