`

Java使用Runtime.exec()给Windows命令提示符做了个外壳,真的很山寨!

阅读更多
    昨天发布的文本编辑器Quickpad-1.2我还有很多地方不满意的,比如控制台没有实现键盘输入功能,今天本想解决这个问题,没想到做成了一个山寨版的Windows命令提示符。

MyConsole的效果如下





下面将代码贴出来,以作备忘。

MyConsole.java
package com.jison.MyConsole;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

/**
 * 命令提示符的外壳程序
 * @version	MyConsole-1.0
 * @author	jison
 * @email	jisonami@163.com
 * @time	2015-1-30
 */
public class MyConsole {

	/**
	 * MyConsole主窗体
	 */
	private JFrame jf = new JFrame("MyConsole");
	
	/**
	 * MyConsole的终端文本区
	 */
	private JTextArea consoleTextArea = new JTextArea();
	
	/**
	 * 将终端文本区加入到JScrollPane
	 */
	private JScrollPane jScrollPane = new JScrollPane(consoleTextArea);
	
	/**
	 * 设置默认字体为等宽字体
	 */
	private final Font DEFAULT_FONT = new Font(Font.MONOSPACED, Font.PLAIN, 13);
	
	/**
	 * 控制器对象
	 */
	private MyConsoleControl myConsoleControl;
	
	/**
	 * 程序入口
	 * @param args
	 */
	public static void main(String[] args){
		new MyConsole();
	}
	
	public MyConsole(){
		//初始化UI
		this.setMyConsoleUI();
		//创建键盘监听
		this.createKeyListener();
		//获取当前路径
		String nowPath = (new File(".")).getAbsolutePath();
		nowPath = nowPath.substring(0, nowPath.length()-2);
		//设置当前路径
		MyConsoleDto.getMyConsoleDto().setNowPath(nowPath);
		
		//获取终端控制器
		myConsoleControl = new MyConsoleControl();
		
		//读取运行cmd命令的信息
		String[] cmdArray = new String[3];
		cmdArray[0] = "cmd";
		cmdArray[1] = "/c";
		cmdArray[2] = "cmd";
		myConsoleControl.execCmdThread(cmdArray, 300, consoleTextArea);
	}
	
	private void setMyConsoleUI(){
		//设置终端文本区的字体和颜色
		consoleTextArea.setBackground(Color.BLACK);
		consoleTextArea.setForeground(Color.LIGHT_GRAY);
		consoleTextArea.setFont(DEFAULT_FONT);
		consoleTextArea.setCaretColor(Color.LIGHT_GRAY);
		//设置终端文本区自动换行
		consoleTextArea.setLineWrap(true);
		
		//垂直滚动条需要时自动出现
		jScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		
		jf.add(jScrollPane);
		jf.setSize(680, 450);
		FrameUtil.setFrameCenter(jf);
		//设置窗口的默认关闭操作,退出应用程序
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.setVisible(true);
	}
	
	/**
	 * 对consoleTextArea创建键盘监听
	 */
	private void createKeyListener(){
		consoleTextArea.addKeyListener(new KeyListener(){
			@Override
			public void keyReleased(KeyEvent e) {
				
				//保护consoleText已打印文本信息不受编辑
				myConsoleControl.protectHasPrintText(consoleTextArea);
					
				if(e.getKeyCode()==KeyEvent.VK_ENTER) {
					//回车键释放时的操作
					//获取已打印的文本
					String hasPrintText = MyConsoleDto.getMyConsoleDto().getStrConsoleText();
					//读取当前文本
					String nowConsoleText = consoleTextArea.getText();
					//执行当前输入的命令
					if(nowConsoleText.length()>hasPrintText.length()){
						//获取当前输入的命令
						String cmdStr = nowConsoleText.substring(hasPrintText.length()).trim();
						
						//给每条命令加入"cmd /c"的前缀
						cmdStr = "cmd /c "+cmdStr;
						//以空格截取输入命令的cmdArray
						String[] cmdArray = cmdStr.split(" ");
						//执行刚刚输入命令
						myConsoleControl.execCmdThread(cmdArray, 30000, consoleTextArea);
					}
				}
			}
			@Override
			public void keyTyped(KeyEvent e) {}
			@Override
			public void keyPressed(KeyEvent e) {}
		});
	}
	

}


MyConsoleControl.java
package com.jison.MyConsole;


import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.text.Document;

/**
 * 处理控制台显示的信息
 * @author	jison
 * @email	jisonami@163.com
 * @time	2015-1-30
 */
public class MyConsoleControl {
	
	/**
	 * 对cd等切换目录的特殊命令的处理
	 * @param cmdArray
	 */
	public void execCdChange(String[] cmdArray){
		//获取当前根目录
		String nowRootDir = MyConsoleDto.getMyConsoleDto().getNowRootDir();
		//当前要切换的目录
		File dir = null;
		//对cd命令进行特殊处理
		if(cmdArray[2].equals("cd")){
			//如果命令数组的长度为4,表明cd命令输入了目录
			if(cmdArray.length==4){
				dir = new File(nowRootDir + cmdArray[3]);
			}
		}
		//切换根驱动器命令
		if(cmdArray[2].length()==2 && cmdArray[2].charAt(1)==':'){
			dir = new File(cmdArray[2]);
		}
		//记录当前目录和上一个目录
		if(dir!=null && dir.exists() && dir.isDirectory()){
			//将当前目录记录为上一个目录
			MyConsoleDto.getMyConsoleDto().setPrePath(MyConsoleDto.getMyConsoleDto().getNowPath());
			//将dir记录为当前目录
			MyConsoleDto.getMyConsoleDto().setNowPath(dir.toString());
		}
	}
	
	/**
	 * 保护已打印文本不受编辑
	 */
	public void protectHasPrintText(JTextArea consoleTextArea){
		//获取已打印的文本
		String hasPrintText = MyConsoleDto.getMyConsoleDto().getStrConsoleText();
		//读取当前终端文本
		String nowConsoleText = consoleTextArea.getText();
		//如果当前终端文本的长度小于已打印文本的长度
		if(consoleTextArea.getText().length()<hasPrintText.length()){
			//恢复已打印的文本
			consoleTextArea.setText(hasPrintText);
		}
		//键盘输入的位置不在‘>’字符之后
		if(consoleTextArea.getText().charAt(hasPrintText.length()-1)!='>'){
			//恢复已打印的文本
			consoleTextArea.setText(hasPrintText);
		}
	}
	
	/**
	 * 以追加的方式打印当前目录信息到consoleTextArea
	 */
	public void printDirInfo(JTextArea consoleTextArea){
		String nowPath = MyConsoleDto.getMyConsoleDto().getNowPath();
		consoleTextArea.append(nowPath+">");
		//记录当前consoleTextArea的文本
		MyConsoleDto.getMyConsoleDto().setStrConsoleText(consoleTextArea.getText());
		//将光标移动到最后
		consoleTextArea.setCaretPosition(consoleTextArea.getText().length());
	}
	
	/**
	 * 在限制时间内执行cmdArray命令
	 * @param cmdArray 命令数组
	 * @param time 时间单位为微秒
	 */
	public void execCmdThread(String[] cmdArray, int time, JTextArea consoleTextArea){
		
		//如果输入的命令为exit,则退出整个程序
		if(cmdArray[2].equals("exit")){
			System.exit(0);
		}
		
		//启动新的线程执行一条命令
		Thread cmdThread = new Thread(new Runnable(){
			@Override
			public void run() {
				outputCapture(cmdArray, consoleTextArea);
			}
		});
		cmdThread.start();
		try {
			cmdThread.join(time);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		//对cd等切换目录的特殊命令的处理
		execCdChange(cmdArray);
		
		//插入一个换行符
		if(!cmdArray[2].equals("cmd")){
			consoleTextArea.append("\n");
		}
		//打印当前目录信息
		printDirInfo(consoleTextArea);
	}
	
	/**
	 * 捕捉cmdArray命令的控制台输出
	 * @param cmdArray
	 */
	public void outputCapture(String[] cmdArray, JTextArea consoleTextArea){
		Process process = null;
		try {
			File dir = new File(MyConsoleDto.getMyConsoleDto().getNowPath());
			// 启动命令行指定程序的新进程
			process = Runtime.getRuntime().exec(cmdArray, null, dir);
		}
		catch(IOException e) {
			System.err.println("创建进程时出错...\n" + e);
			System.exit(1);
		}

		// 获得新进程所写入的流
		InputStream[] inStreams = new InputStream[] {process.getInputStream(),
		process.getErrorStream()};
		//将终端信息追加到consoleTextArea
		this.toTextArea(consoleTextArea, inStreams);
		
		try {
			process.waitFor();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 在jTextArea上显示传入的InputStream数组的信息
	 * @param jTextArea	显示信息的文本区域
	 * @param inStreams 传入要显示的InputStream数组的信息
	 */
	public void toTextArea(JTextArea jTextArea, InputStream[] inStreams){
		for(int i = 0; i < inStreams.length; ++i){
			startConsoleReaderThread(jTextArea, inStreams[i]);
		}
	}

	/**
	 * 单独启用一个线程对控制台信息的处理
	 * @param jTextArea
	 * @param inputStream
	 */
	private void startConsoleReaderThread(JTextArea jTextArea,
			InputStream inputStream) {
		final BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
		new Thread(new Runnable() {
			public void run() {
				StringBuffer sb = new StringBuffer();
				try {
					String s;
					Document doc = jTextArea.getDocument();
					while((s = br.readLine()) != null) {
						boolean caretAtEnd = false;
						caretAtEnd = jTextArea.getCaretPosition() == doc.getLength() ?
							true : false;
						sb.setLength(0);
						jTextArea.append(sb.append(s).append('\n').toString());
						if(caretAtEnd)
							jTextArea.setCaretPosition(doc.getLength());
					}
				}
				catch(IOException e) {
					JOptionPane.showMessageDialog(null,
						"从BufferedReader读取错误:" + e);
					System.exit(1);
				}
			}
		}).start();
	}
}


MyConsoleDto.java
package com.jison.MyConsole;

/**
 * 数据传输对象
 * @author	jison
 * @email	jisonami@163.com
 * @time	2015-1-30
 */
public class MyConsoleDto {

	/**
	 * 使用单例模式设计
	 */
	private static MyConsoleDto myConsoleDto;
	
	/**
	 * 保存当前consoleTextArea的所有文本
	 */
	private String strConsoleText;
	
	/**
	 * 记录当前的根目录
	 */
	private String nowRootDir;
	
	/**
	 * 记录当前命令行打开的目录
	 */
	private String nowPath;
	
	/**
	 * 记录前一个目录
	 */
	private String prePath;
	
	/**
	 * 通过静态方法返回唯一实例
	 * @return
	 */
	public static MyConsoleDto getMyConsoleDto(){
		if(myConsoleDto==null){
			myConsoleDto = new MyConsoleDto();
		}
		return myConsoleDto;
	}

	/**
	 * 其余所有值的getter和setter方法
	 */
	public String getStrConsoleText() {
		return strConsoleText;
	}
	public void setStrConsoleText(String strConsoleText) {
		this.strConsoleText = strConsoleText;
	}
	public String getNowPath() {
		return nowPath;
	}
	public void setNowPath(String nowPath) {
		this.nowPath = nowPath;
	}
	public String getPrePath() {
		return prePath;
	}
	public void setPrePath(String prePath) {
		this.prePath = prePath;
	}
	public String getNowRootDir() {
		this.setNowRootDir(this.nowPath.substring(0, 2));
		return nowRootDir;
	}
	public void setNowRootDir(String nowRootDir) {
		this.nowRootDir = nowRootDir;
	}
}


FrameUtil.java
package com.jison.MyConsole;

import java.awt.Dimension;
import java.awt.Toolkit;

import javax.swing.JFrame;

/**
 * 使JFrame窗口居中显示
 * @author	jison
 * @email	jisonami@163.com
 * @time	2015-1-30
 */
public class FrameUtil {
	public static void setFrameCenter(JFrame jf){
		//使窗口居中显示
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Dimension screen = toolkit.getScreenSize();
		
		//先乘除,后加减,再位移
		int x = (screen.width-jf.getWidth()) >> 1;
		int y = (screen.height-jf.getHeight() >> 1)-16;
		jf.setLocation(x,y);
	}
}


没了,以上就是全部的代码了。
  • 大小: 49.6 KB
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics