我使用JAVA swing做了一个命令行工具:
使用的核心技术是SwingWorker,运行效果:
核心工具类:
public class ShellSwingWorker extends SwingWorker<Boolean, Character> {
/***
* 执行命令的正常输出(对程序来说是输入)
*/
private BufferedReader br_right = null;
/***
* 执行命令的错误输出(对程序来说是输入)
*/
private BufferedReader br_error = null;
/***
* 进程封装类
*/
private MyProcess myprocess = null;
private char word = ' ';
private int tmp = 0;
private boolean isPrintVerbose = false;
private StringBuffer stringbuf = new StringBuffer();
private JTextPane resultTP = null;
/***
* result textarea' document
*/
private Document docment;
/***
* charset of result
*/
private String encoding;
/***
* logging
*/
protected Logger logger = Logger.getLogger(this.getClass());
/***
* 命令前缀
*/
public ShellSwingWorker(MyProcess myprocess, BufferedReader br) {
this.br_right = br;
this.myprocess = myprocess;
}
/***
* 构造方法.
*
* @param process
* @param textPane
* @param encoding
*/
public ShellSwingWorker(Process process, JTextPane textPane,
String encoding)
{
MyProcess proc = null;
proc=new MyProcess(process);
construct(proc,textPane,encoding);
}
/***
* 构造方法.
*
* @param myprocess
* @param textPane
* @param encoding
*/
public ShellSwingWorker(MyProcess myprocess, JTextPane textPane,
String encoding) {
construct(myprocess, textPane, encoding);
}
private void construct(MyProcess myprocess, JTextPane textPane,
String encoding){
this.myprocess = myprocess;
if (ValueWidget.isNullOrEmpty(encoding)) {
encoding = SystemHWUtil.CURR_ENCODING;
}
this.encoding = encoding;
try {
br_right = new BufferedReader(new InputStreamReader(
myprocess.getInputStream(), this.encoding), 4096);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
br_error = new BufferedReader(new InputStreamReader(
myprocess.getErrorStream(), this.encoding), 4096);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
this.resultTP = textPane;
docment = this.resultTP.getDocument();
}
@Override
protected Boolean doInBackground() throws Exception {
while ((tmp = br_right.read()) != -1) {
word = (char) tmp;
publish(word);
}
while ((tmp = br_error.read()) != -1) {
word = (char) tmp;
publish(word);
}
if (isPrintVerbose)// 是否打印详细信息
{
System.out.println("doInBackground() over");
}
return true;
}
@Override
protected void process(List<Character> chunks) {
for (char temp : chunks) {
{
// System.out.print(temp);
// this.resultTP.setText(this.stringbuf.toString());//效率低
int leng2 = this.stringbuf.length();
try {
// 追加
docment.insertString(leng2, String.valueOf(temp), null);
} catch (BadLocationException e) {
GUIUtil23.warningDialog(e.getMessage());
e.printStackTrace();
}
this.stringbuf.append(temp);
}
}
}
public StringBuffer getStringbuf() {
return stringbuf;
}
/***
* main thread can't execute next command(below waitFor()) until done() is
* executed;if done() hasn't be executed,this.myprocess.waitFor() will wait
*/
@Override
protected void done() {
if (isPrintVerbose) {
System.out.println("done() is executed");
}
if (!ValueWidget.isNullOrEmpty(br_right)) {
try {
br_right.close();
br_error.close();
} catch (IOException e) {
e.printStackTrace();
}
}
String logMesg=this.getClass().getSimpleName()+".done() is executed successfully.";
logger.debug(logMesg);
System.out.println(logMesg);
this.myprocess.stopLoop();
}
public MyProcess getProcess() {
return myprocess;
}
项目采用maven构建,结构如下:
笔记:
遇到的问题
(1)卡了?
<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter"/> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"/> <v:f eqn="sum @0 1 0"/> <v:f eqn="sum 0 0 @1"/> <v:f eqn="prod @2 1 2"/> <v:f eqn="prod @3 21600 pixelWidth"/> <v:f eqn="prod @3 21600 pixelHeight"/> <v:f eqn="sum @0 0 1"/> <v:f eqn="prod @6 1 2"/> <v:f eqn="prod @7 21600 pixelWidth"/> <v:f eqn="sum @8 21600 0"/> <v:f eqn="prod @7 21600 pixelHeight"/> <v:f eqn="sum @10 21600 0"/> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/> <o:lock v:ext="edit" aspectratio="t"/> </v:shapetype><v:shape id="图片_x0020_1" o:spid="_x0000_i1025" type="#_x0000_t75" style='width:340.5pt;height:328.5pt;visibility:visible'> <v:imagedata src="file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image001.png" o:title=""/> </v:shape><![endif]--><!--[if !vml]--><!--[endif]--> |
为什么呢?确实是使用的线程啊?
原因:
@Override protectedvoid process(List<Character> chunks) { for (char temp : chunks) { { // System.out.print(temp); this.stringbuf.append(temp); this.resultTP.setText(this.stringbuf.toString());
} } } |
标红的代码影响性能
解决方法:
<!--[if gte vml 1]><v:shape id="图片_x0020_4" o:spid="_x0000_i1026" type="#_x0000_t75" style='width:414.75pt; height:227.25pt;visibility:visible'> <v:imagedata src="file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image003.png" o:title=""/> </v:shape><![endif]--><!--[if !vml]--><!--[endif]--> |
swingwork中done()方法还没有完全执行完毕,就执行proc.waitFor()后面的语句
使用swingwork 可以在界面上异步的看到执行结果,而不是等待执行完之后才一次性打印出来,影响用户体验。这就是swingwork存在的目的。
解决方法:
对Process进行封装,看下面标黄的代码,若loop为true则会死循环,一直等待。
package com.common.util;
import java.io.InputStream; import java.io.OutputStream;
publicclass MyProcess extends Process { private Process proc; privatebooleanloop=true;
public Process getProc() { returnproc; }
publicboolean isLoop() { returnloop; }
/*** * should be invoked in end */ public int waitFor() throws InterruptedException{ int waitFor_exitcode= proc.waitFor(); /*must wait until ShellSwingWorker.done() is executed. */ while (loop) { Thread.sleep(100); } return waitFor_exitcode; }
publicvoid stopLoop(){ loop=false; }
public OutputStream getOutputStream(){ returnproc.getOutputStream(); }
public InputStream getInputStream(){ returnproc.getInputStream(); }
public InputStream getErrorStream(){ returnproc.getErrorStream(); } public int exitValue(){ returnproc.exitValue(); } public MyProcess(Process proc) { super(); this.proc = proc; }
@Override publicvoid destroy() { this.proc.destroy();
} }
|
那么时候终止循环呢?
在swingwork的done()方法中:
@Override protectedvoid done() { if (isPrintVerbose) { System.out.println("done() is executed"); } if (!ValueWidget.isNullOrEmpty(br_right)) { try { br_right.close(); br_error.close(); } catch (IOException e) { e.printStackTrace(); } } this.myprocess.stopLoop(); } |
下面是有问题的:
Process p3=pb.start(); ShellSwingWorker worker = new ShellSwingWorker(p3, resultTP, encoding); worker.execute(); Process proc = worker.getProcess(); p3.waitFor(); System.out.println("proc.waitFor() is executed."); // result2 = worker.getStringbuf().toString(); int exitCode2 = proc.exitValue(); |
执行结果:
<!--[if gte vml 1]><v:shape id="_x0000_i1027" type="#_x0000_t75" style='width:339pt;height:36pt'> <v:imagedata src="file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image005.png" o:title=""/> </v:shape><![endif]--><!--[if !vml]--><!--[endif]--> |
下面的事正确的:
ShellSwingWorker worker = new ShellSwingWorker(pb.start(), resultTP, encoding); worker.execute(); Process proc = worker.getProcess(); proc.waitFor(); System.out.println("proc.waitFor() is executed."); // result2 = worker.getStringbuf().toString(); int exitCode2 = proc.exitValue(); |
执行结果如下:
<!--[if gte vml 1]><v:shape id="_x0000_i1028" type="#_x0000_t75" style='width:337.5pt;height:37.5pt'> <v:imagedata src="file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image007.png" o:title=""/> </v:shape><![endif]--><!--[if !vml]--><!--[endif]--> |
项目源代码见附件:sh_script_executor.zip