package y2019.m08.d24;
import java.awt.*;
import java.awt.event.*;
import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 简单的计算器
*
* @author luther
* @日期 2019.8.25
* @version 1.0
*
* 有待优化的地方 BUG:
* 1,Button增加回退按键监听
* 2,增加括号运算(),指数运算
* 3,界面优化
* 4,末尾去0和小数点
* 5,文本框全选输入时 覆盖
* 6,增加回退,清空,括号等Button按键
* 7,
* */
public class MyCalc {
public static void main(String[] args) {
new MyCalc().init();
}
/*
多次需要使用的正则表达式,
运算符,减号需要转义,否则表示范围了,如[a-z];
运算数,包含整数或小数
*/
private static final String OPERS = "[\\+\\-\\*/]";
private static final String NUMBER = "((\\d+\\.\\d*)|\\d+)";
//定义是否刚刚进行过计算,用于下一次输入前清空文本框
private boolean isDoCalc = false;
//按键4*4按钮文本
private static final String[] BUTTS = {
"7", "8", "9", "+", "4", "5", "6", "-",
"1", "2", "3", "*", "0", ".", "=", "/"};
//按键4*4按钮
private Button[] bs = new Button[BUTTS.length];
//主窗口,使用默认的5方向管理器
private Frame f = new Frame("计算器");
//输入框
private TextField tf = new TextField(30);
//4*4按键区
private Panel p = new Panel(new GridLayout(4, 4));
/**
* 初始化入口
*/
public void init() {
//输入框背景色,银色
tf.setBackground(new Color(0xE6E8FA));
//输入框注册按键监听器,实现1,ESC退出程序,
//2,计算后,清空文本区;3,Enter回车键进行计算
tf.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
System.exit(0);
}
else if(isDoCalc) {
tf.setText("");
isDoCalc = false;
}
else if(e.getKeyCode() == KeyEvent.VK_ENTER){
doCalc();
}
}
});
//4*4按钮Button监听器
ActionListener bListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("=")) {
doCalc();
}
else{
String cmd = e.getActionCommand();
tf.setText(isDoCalc ? (isDoCalc = false) ? "" : cmd : tf.getText() + cmd);
}
}
};
//4*4按键监听器
KeyAdapter bkListener = new KeyAdapter() {
public void keyPressed(KeyEvent e) {
String code = KeyEvent.getKeyText(e.getKeyCode());
if(code.equals("Enter")) {
doCalc();
}
else if(code.startsWith("NumPad") || code.matches("\\d")) {
code = code.substring(code.length() - 1);
tf.setText(isDoCalc ? (isDoCalc = false) ? "" : code : tf.getText() + code);
}
else{
//System.out.println(code);
}
}
};
//初始化按键,注册监听器ActionListener和KeyListener,并组合成4*4按键区
for(int i = 0; i < BUTTS.length; i++) {
bs[i] = new Button(BUTTS[i]);
bs[i].addActionListener(bListener);
bs[i].addKeyListener(bkListener);
p.add(bs[i]);
}
//Frame注册WindowListener监听器,实现关闭按钮
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
Runtime.getRuntime().exit(0);
}
});
//Frame组合,初始化
f.add(tf, BorderLayout.NORTH);
f.add(p);
f.setLocation(800, 300);
f.pack();
f.setVisible(true);
}
/**
* 获取计算表达式,显示计算结果
*/
private void doCalc() {
tf.setText(recCalc(tf.getText()));
}
/**
* 递归计算recursive algorithm
* @param repre 需要计算的字符串
* @return 计算的结果
*/
private String recCalc(String exp) {
//去掉末尾的小数点和0
//表达式校验1,无法计算的表达式,2只有一个数的表达式,3只需一次计算的表达式,4多次运算
if(!exp.matches("^" + NUMBER + "(" + OPERS + NUMBER + ")*$")) {
isDoCalc = true;
return "无法计算";
}
else if(exp.matches(NUMBER)) {
return exp;
}
else if(exp.matches("^" + NUMBER + OPERS + NUMBER + "$")) {
return simpleCalc(exp);
}
else {
//两个字符串:子计算结果和新表达式,进入该分支必定是包含2个运算符及以上
String subResult = "";
String result = exp;
//获取子表达式,先获取乘除表达式
Matcher m = Pattern.compile(NUMBER + "(\\*|/)" + NUMBER).matcher(exp);
if (m.find()) {
subResult = m.group();
}
else {
m = Pattern.compile(NUMBER + OPERS + NUMBER).matcher(exp);
m.find();
subResult = m.group();
}
//替换子表达式转换成正则表达式即子字符串的+和*需要转义
String regex = subResult.replaceFirst("\\b+(?=[\\+\\*])", "\\\\");
//把子表达式替换成计算结果
result = result.replaceFirst(regex, simpleCalc(subResult));
return recCalc(result);
}
}
/**
* 二目运算,两个数的加减乘除计算,使用BigDecimal的精确计算
* @param repre 两个需要计算的数,中间带一个运算符
* @return 返回计算结果,如果计算失败返回"未知错误!"
* */
private String simpleCalc(String repre) {
//合法性校验
if(!repre.matches(NUMBER + OPERS + NUMBER)) {
return "未知错误1!";
}
//获取运算符
Matcher m = Pattern.compile(OPERS).matcher(repre);
m.find();
String oper = m.group();
//获取2个数字
String[] nums = repre.split(OPERS);
BigDecimal b1 = new BigDecimal(nums[0]);
BigDecimal b2 = new BigDecimal(nums[1]);
//精确计算
switch (oper) {
case "+" :
return b1.add(b2).doubleValue()+"";
case "-" :
return b1.subtract(b2).doubleValue()+"";
case "*" :
return b1.multiply(b2).doubleValue()+"";
case "/" :
return b1.divide(b2, 20, BigDecimal.ROUND_HALF_UP).doubleValue()+"";
default :
return "未知错误2!";
}
}
}
自己写了一整天,希望大佬能够指点一下,提供下示例代码也好啊
非常感谢!