概要
利用awt完成计算器gui设计。
利用中缀转后缀表达式的方法实现带括号的混合运算。
能通过界面按钮控件输入并实现算术表达式,输入的表达式即时在控件中显示,按下“=”按钮能实现运算,并将运算结果输出在控件中显示;要求能保存和浏览历史表达式的运算记录。
GUI设计
设计两个文本框,上文本框进行算式的事实更新,下文本框用于显示当前的输入以及最后的结果。
通过CE按钮清空上下文本框。
通过Del按钮回退一个操作。
通过“历史”或“记录”这两个按钮打开新窗口,里面保存了之前的算式和结果。
±符号用于正负运算。
“.”小数点用于包含小数的运算数。
根据表达式长度动态改变上下文本框字体大小,以保证上下文本框内容能在文本框中完整显示。
剩下的数字以及加减乘除和左右括号不多做解释。
计算器实现的功能
1.简单的表达式计算,包括 + - * /运算符,正负号百分数及括号功能,以及退格,清空。
2.输入表达式时自动更新上下两文本框(仿Windows自带计算器界面),并将最后的运算结果显示在下方文本框,将表达式显示在上方文本框。
3.简单的表达式检查功能,能够检查括号不匹配、除以零等部分表达式错误。
4.运算符输入限制和辅助:连续输入运算符时,不会连续向表达式中添加运算符,而是进行运算符更新
5.小数点限制:在一个运算数中若输入小数点则小数点按键暂时失效,以保证每个运算数只有一个小数点;另外,当按下小数点时,若下方文本框中没有内容或者仅有运算符,则自动在小数点前添加数字0。
6.数字及小数点输入限制和辅助:输入右括号之后数字键及小数点键暂时失效,输入运算符之后重新激活。
7.允许输入多层括号,将按照优先级进行计算。
计算器未能实现的功能
在缺失右括号时自动补上右括号。
BUG
1.数字后面可以加‘(’。
解决方案:数字后按‘(’时在左括号前加乘号。
2.‘(’后可以加操作符。
解决方案:添加约束条件,下文本框第一个字符是左括号时,运算符失效(因为左括号永远在下文本框的第一位)
3.按了“历史记录”按钮后小数点失效。
解决方案:给历史记录添加条件,并且与其他按钮的调剂同级
4.“历史记录”按钮被当做操作符。
解决方案:同上
5.运算符后直接接右括号
解决方案:加约束条件,最后一个字符如果是运算符或者小数点则右括号失效。
6.数字后可以加右括号
解决方案:增加限制条件,下文本框开头如果非左括号则右括号失效。
7.历史记录只显示最近的一次运算。
解决方案:设x用来保存每次的计算结果。
x = x+"\r\n" +strUpper+"="+strUnder;
8.历史记录中按过等号就会被记录。
解决方案:进行判断,如果下文本框或者上文本框为空,则x = x(待优化),最终效果如下
9.加了左括号没加右括号,点击等号报错,用户友好型差。
解决方案:暂未解决,目前无法做到自动添加括号。
10.右括号之后不能再加运算符和数字。按了等号后不输出结果。
解决方案:找到问题代码,在解决左括号后可以加运算符的bug时添加了这条约束,导致bug,具体原因不明。但是推测bug是因为按下右括号后,下文本框空,上不空导致的。于是在这条约束中添加下不空的条件,最终解决了bug。
解决前:
解决后:
11.如图,小数点后可以直接接运算符。
解决方案:增加约束条件
else if (!strUnder.isEmpty()&&strUnder.charAt(strUnder.length()-1)=='.'){}
12.第一个字符不能是左括号
解决方案:目前找到问题是出在这段代码。
if ((strUnder.charAt(strUnder.length()-1)<='9')&&(strUnder.charAt(strUnder.length()-1)>'0')){//如果数字后按左括号
//则会自动在左括号前加乘号
strUpper = strUnder+"*";
strUnder = cmd;
}
else if (strUnder.charAt(strUnder.length()-1)=='.'){}//小数点后不能直接加左括号
此代码原本是用来解决bug1以及小数点后可以接左括号的bug的。推测是 当下文本框为空时,限制条件则失效报错。于是添加新的限制条件“当下文本框非空”后问题解决。
新代码如下:
else if(cmd.equals("(")) {
if ((!strUnder.isEmpty())&&(strUnder.charAt(strUnder.length()-1)<='9')&&(strUnder.charAt(strUnder.length()-1)>'0')){//如果数字后按左括号
//则会自动在左括号前加乘号
strUpper = strUnder+"*";
strUnder = cmd;
}
else if ((!strUnder.isEmpty())&&strUnder.charAt(strUnder.length()-1)=='.'){}//小数点后不能直接加左括号
else{
strUpper += strUnder;
strUnder = cmd;
}
}
13.小数点后直接加左括号运算出错
解决方案:增加约束条件,使小数点后不能接左括号。
else if (strUnder.charAt(strUnder.length()-1)=='.'){}
算法(单栈法)
左右括号匹配,利用栈sta来解决。从前往后遍历式子,如果遇到左括号入栈,遇到右括号,左括号出栈。如果栈空或者栈顶非左括号,则说明右括号多了,返回false。同理若遍历结束后栈非空,说明左括号多了,返回false。
计算式将中缀表达式转换为后缀表达式,并在运算数与运算符之间添加分隔符$,最后进行后缀表达式的计算。中缀表达式储存在str中,后缀表达式储存在s中。
数字与运算符直接用$隔开。数字直接进s。
看到左括号直接入栈。
栈空直接入栈。
优先级高的符号直接入栈。
加号和减号优先级只比左括号高,所以只需判断是否空栈或者是否栈顶为左括号,若是,则入栈,若不是,则弹出,进s并加$号与下一个数字或字符隔开。
乘号和除号优先级比加减和左括号高,所以只需判断是否为空栈或者是否栈顶为乘号或除号,若是,则弹出,进s并加$号与下一个数字或字符隔开,若不是,则入栈。
遇到右括号,将栈顶弹出,进s并加$号与下一个数字或字符隔开,直到遇到左括号,将左括号弹出。
式子结束后将栈内剩余运算符弹出,进s并加$号与下一个数字或字符隔开。
后缀表达式运算:遇到操作数入栈,遇到操作符,将栈顶两个操作数运算后再放入栈。