一.实现原理
- 获取计算表达式:用户点击button,显示器的值则push(button的值)。
但push有要求:如果是括号或者运算符,则再其前后各+一个空格字符串,再push - 创建一个储存运算符的集合(栈1)记作symbols,一个储存新的表达式的集合(栈2)记作newExpre。
-
对获取的表达式进行遍历,利用switch来进行判断,规则简单说明:
I. 遇到'(',直接push到symbols
II. 遇到‘)’ 从symbols最后一个开始,挨个pop,并push到newExpre中。直到遇到第一个‘(’结束。
III. 遇到运算符:- 若symbols为空,则直接将该运算符push到symbols中
-
比较其余symbols最后一个运算符的优先级,
若前者低于后者,则将后者从symbols中pop,再push到 newExpore中,重复此操作,一直到该运算符的优先级>symbols中 最后一个运算符的优先级(或symbols为空),然后将前 者push到symbols中。结束
- 否则,直接将其push到symbols中.
IV. 其它情况,直接push到newExpore中
- 遍历结束,将symbols从最后一个到第一个,挨个push到newExpre中。
-
计算,遍历newExpre:
遇到运算符,根据该运算符 计算该运算符前两位的和/差/乘/除,结果存在该运算符前两位,在删除该运算符前一位,以及该运算符
注意: push表示集合的add()函数,pop表示集合的pollLast()函数。此处用的js数组相同功能的函数名
二.版本、工具等简单介绍
- 本文用到的是java-8.0.16版本,IDE用的软件IDEA
- 计算器继承了窗口类Frame,代码涉及JAVA的数据类型转换、字符串操作、集合linkedList操作、正则表达式、按钮自动生成、各种循环、
判断用户简单的输入错误(例如少了括号),并自动修复功能等。 - 运算符号比较原则:"-"=="+" > "*"=="/"。
三.完整代码
package calculator;
import java.awt.*;
import java.awt.event.*;
import java.util.LinkedList;
import javax.swing.*;
public class calculator {
public static void main(String[] args) { new CalculatorFrame("计算器"); }
}
//计算器的窗口
class CalculatorFrame extends Frame{
private final int height=400;
private final int width=700;
private final int offset_x=20;
private final int offset_y=40;
private TextArea display,record;//显示屏与历史记录
private String nullMessage="尚无历史记录...";
//组件value
private final String[] values={"(",")","C","Back","7","8","9","/","4","5","6","*","1","2","3","+","0",".","=","-"};
//构造函数,本计算器入口
public CalculatorFrame(String title){
//this.setTitle(title);
super(title);//设置计算器名字
setMainFrame();//窗口基本设定
setButton();//设置按钮
}
private void setMainFrame(){
this.setLayout(null);//设置窗口布局为空
this.setBounds(400,200,width,height);//设置显示位置,设置窗口大小
this.setResizable(false);//窗口是否可调整大小
this.setVisible(true);//窗口可视
//关闭窗口监听事件
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
//设置显示屏
display=new TextArea("0",8,52,3);//textarea
display.setBounds(offset_x,offset_y,(int)(width*0.7),(int)(height*0.3));
display.setEditable(false);
display.setBackground(new Color(230, 230, 230));
display.setFont(new Font("幼圆",Font.BOLD,15));
this.add(display);
//设置历史记录
record=new TextArea(nullMessage,52,52,3);
int left=offset_x+(int)(width*0.7);
record.setBounds(left,offset_y,width-left,height-offset_y);
record.setEditable(false);
record.setBackground(new Color(230, 230, 230));
record.setFont(new Font("幼圆",Font.TYPE1_FONT,10));
//清空历史记录的按钮
JButton delBtn=new JButton(new ImageIcon("src/images/del.png"));//给按钮增加背景图片
delBtn.setBounds(width-40,height-40,20,20);//按钮大小,以及定位
delBtn.setBackground(new Color(255,255,255));//设置一个默认的背景颜色
delBtn.addMouseListener(new MouseAdapter(){
@Override
//鼠标点击,清空历史记录
public void mousePressed(MouseEvent e){
record.setText(nullMessage);
}
});
this.add(delBtn);
this.add(record);
}
private void setButton(){
//显示屏
int btn_width=(int)(width*0.7)/4;
int btn_height=(int)(height*0.7-offset_y)/5;
for(int i=0;i<values.length;i++){
addButton(values[i],offset_x+btn_width*(i%4),5+offset_y+(int)(height*0.3)+btn_height*(int)(Math.floor(i/4)));
}
}
private void addButton(String val,int x,int y){
final Button btn=new Button(val);
btn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
btn.setBounds(x,y,(int)(width*0.7)/4-5,(int)(height*0.7-offset_y)/5-5);
btn.setFont(new Font("标楷体", Font.BOLD, 15));
//增加点击事件
btn.addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent e) {
final String[] exceptMessages={"NaN","Infinity"};
Button Btn=(Button)e.getSource();//获取到点击的按钮对象
String value=Btn.getLabel();//按钮的值
String expression=display.getText();//获取显示屏的表达式
int len=expression.length();//因为经常使用表达式长度,故在此提前声明
switch (value){
case "C":
display.setText("0");
break;
case "Back":
boolean flag=false;
for(int i=0;i<exceptMessages.length;i++){
if(!expression.equals(exceptMessages[i])) continue;
flag=true;
break;
}
if(len==1) expression="0";
else if(flag==true){
//存在无穷,NaN等数据时
expression="0";
} else if(len>0 &&expression.lastIndexOf(" ")!=len-1 ){
expression=expression.substring(0,len-1);
}else if(len>0 &&expression.substring(len-4,len-3).matches("[0-9]+")) expression=expression.substring(0,len-3);
else if(len>0) expression=expression.substring(0,len-2);
display.setText(expression);
break;
case "+":
case "-":
case "*":
case "/":
if(expression.lastIndexOf(" ")==len-1 &&!expression.substring(len-2,len-1).equals("(")
&&!expression.substring(len-2,len-1).equals(")")){
expression=expression.substring(0,len-3);
}else if(len>1&& expression.substring(len-2,len-1).equals("(")){
expression+="0";
}
expression+=" "+value+" ";
display.setText(expression);
break;
case "(":
case ")":
if(value.equals(")") &&hasNums(expression,"(")<=hasNums(expression,")")) break;
else if(value.equals(")") &&expression.lastIndexOf(" ")==len-1 &&expression.lastIndexOf("(")!=len-2){
//形如 2+(5+ 的情况,自动加一个数
expression=autoAdd(expression);
len+=1;
}
if(expression.equals("0")) expression="";
else if(value=="(" &&expression.lastIndexOf(" ")!=len-1) expression+=" *";//5*(2+3)默认给个*号
if(expression.lastIndexOf(" ")==len-1) expression=expression.substring(0,len-1);//清除前面的空格
if(len>1 &&value.equals("(") && expression.lastIndexOf(")")==len-2){
//形如 (a+b)*(c+d) 中间加个*
expression+=" *";
len+=2;
}
expression+=" "+value+" ";
display.setText(expression);
break;
case ".":
if(expression.lastIndexOf(")")!=-1 && expression.lastIndexOf(")")==len-2) expression+="* 0"+value;//括号
else if(expression.lastIndexOf(" ")==len-1)expression+="0"+value;
else if(expression.lastIndexOf(".")!=-1 &&expression.lastIndexOf(".")>expression.lastIndexOf(" ")) break;//连续输入两个.
else expression+=value;
display.setText(expression);
break;
case "=":
if(hasNums(expression,"(")>hasNums(expression,")")){
//少了gapNum个括号
expression+=expression.lastIndexOf(" ")==len-1?"+ 0":" + 0";
int gapNum=hasNums(expression,"(")-hasNums(expression,")");
for(int i=0;i<gapNum;i++){
expression+=" ) ";
}
}
else if(expression.lastIndexOf(" ")==len-1 && expression.lastIndexOf(")")!=len-2){
//最后一个为运算符的时候,默认再表达式加个0或1
expression=autoAdd(expression);
}
cal(expression);
break;
default:
//exceptMessages
if(expression.substring(len-1).matches("[a-zA-Z]+")){
expression="0";
}
//数字
if(expression.equals("0")) expression="";
if(expression.lastIndexOf(" ")==len-1&&expression.lastIndexOf(")")==len-2) expression+="* ";
expression+=value;
display.setText(expression);
}
}
});
this.add(btn);
}
//计算
private void cal(String str){
//得到新的表达式
LinkedList<String> expre=getNewExpre(str.split(" "));
for(int i=0;i<expre.size();i++){
System.out.print(expre.get(i)+",");
}
System.out.println();
for(var i=0;i<expre.size();i++){
var val=expre.get(i);
switch(val){
case "-":
expre.set(i-2,String.valueOf(Double.valueOf(expre.get(i-2).toString())-Double.valueOf(expre.get(i-1).toString())));
expre.remove(i-1);
expre.remove(i-1);
i-=2;
break;
case "+":
expre.set(i-2,String.valueOf(Double.valueOf(expre.get(i-2).toString())+Double.valueOf(expre.get(i-1).toString())));
expre.remove(i-1);
expre.remove(i-1);
i-=2;
break;
case "*":
expre.set(i-2,String.valueOf(Double.valueOf(expre.get(i-2).toString())*Double.valueOf(expre.get(i-1).toString())));
expre.remove(i-1);
expre.remove(i-1);
i-=2;
break;
case "/":
expre.set(i-2,String.valueOf(Double.valueOf(expre.get(i-2).toString())/Double.valueOf(expre.get(i-1).toString())));
expre.remove(i-1);
expre.remove(i-1);
i-=2;
break;
default:
break;
}
}
String result=expre.get(0);
display.setText(result);//归零
//增加历史记录
String recordStr=record.getText();
if(recordStr.equals(nullMessage)) recordStr="";
recordStr+=str+"="+result+"\n\n";
record.setText(recordStr);
}
//0.0+5*(5+0.5)*0.5
//得到新的表达式
private LinkedList<String> getNewExpre(String[] expression){
for(int i=0;i<expression.length;i++){
System.out.print(expression[i]+",");
}
System.out.println();
LinkedList<String> symbols=new LinkedList<>();//存放符号的栈
LinkedList<String> newExpre=new LinkedList<>();//存放新的表达式的栈
for (int i=0;i<expression.length;i++){
String val=expression[i];
if(val.equals("")) continue;
System.out.println(symbols);
System.out.println(newExpre);
switch (val){
case "(":symbols.add(val);break;
case ")":
boolean isOk=true;
while(isOk){
String _symbol=symbols.pollLast();
if(_symbol.equals("(")) isOk=false;
else newExpre.add(_symbol);
};
break;
case "+":
case "-":
case "*":
case "/":
if(symbols.size()==0){
symbols.add(val);
} else if(compareSymbols(val,symbols.get(symbols.size()-1))) symbols.add(val);
else{
while (symbols.size()>0 && !compareSymbols(val,symbols.get(symbols.size()-1))){
newExpre.add(symbols.pollLast());//需要全部出栈,直到遇到优先级比自己小的.
}
symbols.add(val);
}
break;
default:
newExpre.add(val);
}
}
while(symbols.size()>0){
newExpre.add(symbols.pollLast());
}
return newExpre;
}
//比较符号优先级
private boolean compareSymbols(String newSymbol,String existSymbol){
//只可能传入 +,-,*,/
//false 表示要前者优先级更小或相等,符号栈最后一个元素需要出栈
//true 表示前者优先级更高,符号直接进符号栈
//遇到括号
if(existSymbol.equals("(")) return true;
//同优先级
if(newSymbol.equals(existSymbol)) return false;
else if((newSymbol.equals("*")||newSymbol.equals("/"))&&(existSymbol.equals("*")||existSymbol.equals("/"))) return false;
else if((newSymbol.equals("+")||newSymbol.equals("-"))&&(existSymbol.equals("+")||existSymbol.equals("-"))) return false;
//不同优先级
else if((newSymbol.equals("-") ||newSymbol.equals("+")) &&(existSymbol.equals("*") || existSymbol.equals("/"))) return false;
// 只剩下情况: 前者*或/ 遇到 后者+或*
return true;
}
//判断str中有多少个val
private int hasNums(String str,String val){
int nums=0;
while (str.indexOf(val)!=-1){
nums+=1;
str=str.substring(str.indexOf(val)+1);
}
return nums;
}
//表达式常见错误,自动再后边加0 或者1
private String autoAdd(String expression){
String symbol=expression.substring(expression.length()-2,expression.length()-1);
switch (symbol){
case "+":
case "-":
expression+="0";
break;
case "*":
default:
expression+="1";
}
return expression;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。