昨天发布的文本编辑器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 [email protected]
* @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 [email protected]
* @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 [email protected]
* @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 [email protected]
* @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);
}
}
没了,以上就是全部的代码了。