我使用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