如何在 GUI 面板内创建 Java 控制台的实例?
raman
问问题
77529 次
5 回答
71
这是一个正常运行的类。您可以使用以下方法将其实例安装到系统中并出错:
PrintStream con=new PrintStream(new TextAreaOutputStream(...));
System.setOut(con);
System.setErr(con);
2014-02-19 更新:使用 EventQueue.invokeLater() 来避免 GUI 线程问题,这些问题很少会出现在原始版本中。
2014-02-27 更新:更好的实施
更新于 2014-03-25:正确记录和删除文本区域中的行,run()
以避免在控制台被输出淹没时可能发生的追加和删除之间的竞争条件。最终结果对我来说似乎也更干净。
import java.awt.*;
import java.io.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
public class TextAreaOutputStream
extends OutputStream
{
// *************************************************************************************************
// INSTANCE MEMBERS
// *************************************************************************************************
private byte[] oneByte; // array for write(int val);
private Appender appender; // most recent action
public TextAreaOutputStream(JTextArea txtara) {
this(txtara,1000);
}
public TextAreaOutputStream(JTextArea txtara, int maxlin) {
if(maxlin<1) { throw new IllegalArgumentException("TextAreaOutputStream maximum lines must be positive (value="+maxlin+")"); }
oneByte=new byte[1];
appender=new Appender(txtara,maxlin);
}
/** Clear the current console text area. */
public synchronized void clear() {
if(appender!=null) { appender.clear(); }
}
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)); }
}
@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 MEMBERS
// *************************************************************************************************
static class Appender
implements Runnable
{
private final JTextArea textArea;
private final int maxLines; // maximum lines allowed in text area
private final LinkedList<Integer> lengths; // length of lines within text area
private final List<String> values; // values waiting to be appended
private int curLength; // length of current line
private boolean clear;
private boolean queue;
Appender(JTextArea txtara, int maxlin) {
textArea =txtara;
maxLines =maxlin;
lengths =new LinkedList<Integer>();
values =new ArrayList<String>();
curLength=0;
clear =false;
queue =true;
}
synchronized void append(String val) {
values.add(val);
if(queue) { queue=false; EventQueue.invokeLater(this); }
}
synchronized void clear() {
clear=true;
curLength=0;
lengths.clear();
values.clear();
if(queue) { queue=false; EventQueue.invokeLater(this); }
}
// MUST BE THE ONLY METHOD THAT TOUCHES textArea!
public synchronized void run() {
if(clear) { textArea.setText(""); }
for(String val: values) {
curLength+=val.length();
if(val.endsWith(EOL1) || val.endsWith(EOL2)) {
if(lengths.size()>=maxLines) { textArea.replaceRange("",0,lengths.removeFirst()); }
lengths.addLast(curLength);
curLength=0;
}
textArea.append(val);
}
values.clear();
clear =false;
queue =true;
}
static private final String EOL1="\n";
static private final String EOL2=System.getProperty("line.separator",EOL1);
}
} /* END PUBLIC CLASS */
这是它的截图:
于 2008-12-05T05:47:35.090 回答
25
@软件猴子:
有用!:)
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class Main{
public static void main( String [] args ) throws InterruptedException {
JFrame frame = new JFrame();
frame.add( new JLabel(" Outout" ), BorderLayout.NORTH );
JTextArea ta = new JTextArea();
TextAreaOutputStream taos = new TextAreaOutputStream( ta, 60 );
PrintStream ps = new PrintStream( taos );
System.setOut( ps );
System.setErr( ps );
frame.add( new JScrollPane( ta ) );
frame.pack();
frame.setVisible( true );
frame.setSize(800,600);
for( int i = 0 ; i < 100 ; i++ ) {
System.out.println( i );
Thread.sleep( 500 );
}
}
}
于 2008-12-05T07:01:18.390 回答
4
我知道这是一个旧线程,但我在试图找出一种好的方法时发现它的事实意味着其他人可能也会这样做。
这是一种(可能)更清洁的方式来做软件猴子发布的内容:
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import javax.swing.JTextArea;
/**
* Represents a console viewable through a <code>JTextArea</code>.
*
* <p>
* Implementation:
* <code>
* System.setOut(new PrintStream(new Console( ... )));
* </code>
* </p>
*
* @author Derive McNeill
*
*/
public class Console extends OutputStream {
/**
* Represents the data written to the stream.
*/
ArrayList <Byte> data = new ArrayList <Byte> ();
/**
* Represents the text area that will be showing the written data.
*/
private JTextArea output;
/**
* Creates a console context.
* @param output
* The text area to output the consoles text.
*/
public Console(JTextArea output) {
this.output = output;
}
/**
* Called when data has been written to the console.
*/
private void fireDataWritten() {
// First we loop through our written data counting the lines.
int lines = 0;
for (int i = 0; i < data.size(); i++) {
byte b = data.get(i);
// Specifically we look for 10 which represents "\n".
if (b == 10) {
lines++;
}
// If the line count exceeds 250 we remove older lines.
if (lines >= 250) {
data = (ArrayList<Byte>) data.subList(i, data.size());
}
}
// We then create a string builder to append our text data.
StringBuilder bldr = new StringBuilder();
// We loop through the text data appending it to the string builder.
for (byte b : data) {
bldr.append((char) b);
}
// Finally we set the outputs text to our built string.
output.setText(bldr.toString());
}
@Override
public void write(int i) throws IOException {
// Append the piece of data to our array of data.
data.add((byte) i);
// Indicate that data has just been written.
fireDataWritten();
}
}
于 2012-10-17T16:17:51.620 回答
2
ByteArrayOutputStream可用于省略缓冲内容。
private void redirectConsoleTo(final JTextArea textarea) {
PrintStream out = new PrintStream(new ByteArrayOutputStream() {
public synchronized void flush() throws IOException {
textarea.setText(toString());
}
}, true);
System.setErr(out);
System.setOut(out);
}
您可以将ByteArrayOutputStream#reset()绑定到某个按钮,而不是限制行数。
private void redirectConsoleWithClearButton(final JTextArea textarea, JButton clearButton) {
final ByteArrayOutputStream bytes = new ByteArrayOutputStream() {
public synchronized void flush() throws IOException {
textarea.setText(toString());
}
};
clearButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
bytes.reset();
}
});
PrintStream out = new PrintStream(bytes, true);
System.setErr(out);
System.setOut(out);
}
于 2012-11-10T11:05:00.820 回答
1
我最近在我的一个项目中使用了Lawrence Dol提供的优秀代码。
但是,在我的情况下,代码消耗了太多内存。我设法通过替换JTextarea
为JLabel
.
我的内存节省搜索表明,JTextarea
内部代码往往会占用太多时间发送的实际文本。因此,所有这些文本都不能被垃圾收集。
这是初始代码的灵活版本(线程同步被锁取代)。
JComponentOutputStream.java
import java.awt.EventQueue;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JComponent;
public class JComponentOutputStream extends OutputStream {
// *************************************************************************************************
// INSTANCE MEMBERS
// *************************************************************************************************
private byte[] oneByte; // array for write(int val);
private Appender appender; // most recent action
private Lock jcosLock = new ReentrantLock();
public JComponentOutputStream(JComponent txtara, JComponentHandler handler) {
this(txtara, 1000, handler);
}
public JComponentOutputStream(JComponent txtara, int maxlin, JComponentHandler handler) {
if (maxlin < 1) {
throw new IllegalArgumentException("JComponentOutputStream maximum lines must be positive (value=" + maxlin + ")");
}
oneByte = new byte[1];
appender = new Appender(txtara, maxlin, handler);
}
/** Clear the current console text area. */
public void clear() {
jcosLock.lock();
try {
if (appender != null) {
appender.clear();
}
} finally {
jcosLock.unlock();
}
}
public void close() {
jcosLock.lock();
try {
appender = null;
} finally {
jcosLock.unlock();
}
}
public void flush() {
// sstosLock.lock();
// try {
// // TODO: Add necessary code here...
// } finally {
// sstosLock.unlock();
// }
}
public void write(int val) {
jcosLock.lock();
try {
oneByte[0] = (byte) val;
write(oneByte, 0, 1);
} finally {
jcosLock.unlock();
}
}
public void write(byte[] ba) {
jcosLock.lock();
try {
write(ba, 0, ba.length);
} finally {
jcosLock.unlock();
}
}
public void write(byte[] ba, int str, int len) {
jcosLock.lock();
try {
if (appender != null) {
appender.append(bytesToString(ba, str, len));
}
} finally {
jcosLock.unlock();
}
}
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 MEMBERS
// *************************************************************************************************
static class Appender implements Runnable {
private final JComponent swingComponent;
private final int maxLines; // maximum lines allowed in text area
private final LinkedList<Integer> lengths; // length of lines within
// text area
private final List<String> values; // values waiting to be appended
private int curLength; // length of current line
private boolean clear;
private boolean queue;
private Lock appenderLock;
private JComponentHandler handler;
Appender(JComponent cpt, int maxlin, JComponentHandler hndlr) {
appenderLock = new ReentrantLock();
swingComponent = cpt;
maxLines = maxlin;
lengths = new LinkedList<Integer>();
values = new ArrayList<String>();
curLength = 0;
clear = false;
queue = true;
handler = hndlr;
}
void append(String val) {
appenderLock.lock();
try {
values.add(val);
if (queue) {
queue = false;
EventQueue.invokeLater(this);
}
} finally {
appenderLock.unlock();
}
}
void clear() {
appenderLock.lock();
try {
clear = true;
curLength = 0;
lengths.clear();
values.clear();
if (queue) {
queue = false;
EventQueue.invokeLater(this);
}
} finally {
appenderLock.unlock();
}
}
// MUST BE THE ONLY METHOD THAT TOUCHES the JComponent!
public void run() {
appenderLock.lock();
try {
if (clear) {
handler.setText(swingComponent, "");
}
for (String val : values) {
curLength += val.length();
if (val.endsWith(EOL1) || val.endsWith(EOL2)) {
if (lengths.size() >= maxLines) {
handler.replaceRange(swingComponent, "", 0, lengths.removeFirst());
}
lengths.addLast(curLength);
curLength = 0;
}
handler.append(swingComponent, val);
}
values.clear();
clear = false;
queue = true;
} finally {
appenderLock.unlock();
}
}
static private final String EOL1 = "\n";
static private final String EOL2 = System.getProperty("line.separator", EOL1);
}
public interface JComponentHandler {
void setText(JComponent swingComponent, String text);
void replaceRange(JComponent swingComponent, String text, int start, int end);
void append(JComponent swingComponent, String text);
}
} /* END PUBLIC CLASS */
示例使用
JLabel console = new JLabel();
JComponentOutputStream consoleOutputStream = new JComponentOutputStream(console, new JComponentHandler() {
private StringBuilder sb = new StringBuilder();
@Override
public void setText(JComponent swingComponent, String text) {
sb.delete(0, sb.length());
append(swingComponent, text);
}
@Override
public void replaceRange(JComponent swingComponent, String text, int start, int end) {
sb.replace(start, end, text);
redrawTextOf(swingComponent);
}
@Override
public void append(JComponent swingComponent, String text) {
sb.append(text);
redrawTextOf(swingComponent);
}
private void redrawTextOf(JComponent swingComponent) {
((JLabel)swingComponent).setText("<html><pre>" + sb.toString() + "</pre></html>");
}
});
PrintStream con = new PrintStream(consoleOutputStream);
System.setOut(con);
System.setErr(con);
// Optional: add a scrollpane around the console for having scrolling bars
JScrollPane sp = new JScrollPane( //
console, //
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, //
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED //
);
myPanel.add(sp);
于 2015-01-02T04:13:55.790 回答