一、处理系统输出的系统重新连接填充到一个inputstream,以供第二部的JtextArea组建读取数据并显示;
具体思路:new一个新的线程处理SYSTEM.OUT的数据。通过管道输出流与输入流连接,将数据传输到一个PipedInputStream。
LoopedStreams.java
package ywcai.ls.data;
import java.io.*;
public class LoopedStreams {
private PipedOutputStream pipedOS =
new PipedOutputStream();
private boolean keepRunning = true;
private ByteArrayOutputStream byteArrayOS =
new ByteArrayOutputStream(1024) {
public void close() {
keepRunning = false;
try {
super.close();
pipedOS.close();
}
catch(IOException e) {
System.exit(1);
}
}
};
private PipedInputStream pipedIS = new PipedInputStream() {
public void close() {
keepRunning = false;
try {
super.close();
}
catch(IOException e) {
System.exit(1);
}
}
};
public LoopedStreams() throws IOException {
pipedIS.connect(pipedOS);
startByteArrayReaderThread();
}
public InputStream getInputStream() {
return pipedIS;
}
public OutputStream getOutputStream() {
return byteArrayOS;
}
private void startByteArrayReaderThread() {
new Thread(new Runnable() {
public void run() {
while(keepRunning) {
if(byteArrayOS.size() > 0) {
byte[] buffer = null;
synchronized(byteArrayOS) {
buffer = byteArrayOS.toByteArray();
byteArrayOS.reset(); // 清除缓冲区
}
try {
pipedOS.write(buffer, 0, buffer.length);
}
catch(IOException e) {
System.exit(1);
}
}
else
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}).start();
}
}
二、继承一个JTextArea类,重定向system.out数据,并读取。
package ywcai.ls.data;
import java.io.*;
import javax.swing.*;
public class ConsoleText extends JTextArea
{
private static final long serialVersionUID = 1L;
/**
*
*/
public ConsoleText() {
LoopedStreams ls = null;
try {
ls = new LoopedStreams();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
PrintStream ps = new PrintStream(ls.getOutputStream(),true);
System.setOut(ps);
System.setErr(ps);
startConsoleReaderThread(ls.getInputStream());
}
private void startConsoleReaderThread(InputStream inStream)
{
final BufferedReader br =new BufferedReader(new InputStreamReader(inStream));
new Thread(new Runnable() {
public void run() {
StringBuffer sb = new StringBuffer();
try {
String s;
while( (s=br.readLine()) != null) {
sb.setLength(0);
append(sb.append(s).append("\n").toString());
setCaretPosition(getText().length());
}
}
catch(Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
三、在主程序创建consoleTextArea实例
代码省略;
四、问题:
处理按纽点击事件,所有的信息均需要等待按纽时间处理完成后,consoleTextArea才能显示控制台信息,而且是一次性显示;
开始一直以为是LoopedStreams 处理的方式有问题。
最后发现原因:swing在处理事件时,由于UI更新与按纽点击等事件都属于EDT类事件处理线程,需按队列进行处理,因此当时间进行耗时较长操作时就会感觉客户端无响应。
五、解决办法:
在编写点击事件处理实务代码时,新开辟一个工作线程进行处理,这样UI更新无需等待时间处理完毕,即可达到同步输出控制台信息的需求。
button_sub.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Thread(new Runnable() {//开辟一个工作线程
@Override
public void run() {
updateAll();//需处理的实务
}
}).start();
}
});