package Caculator;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.math.BigDecimal;
import java.math.MathContext;
import javax.swing.JFrame;
import com.sun.glass.events.WindowEvent;
public class MyCalculator {
public static void main(String[] args) {
new MyCalculator().launch();
}
public boolean result=false;//输入#之后result变为真,此时可以计算结果了,用于判断能否进行计算。
public boolean end=false;//前面有内容的时候才将其变为true,且输入#之后什么都不能输入了。
/**
* 首先对这几个boolean变量进行具体阐述:rusult只有在#(结束符)输入之后才会赋为true,也就是说只有输入#之后才能输入==;
* end用于#(结束符)能否进行输入,#前必须为正确的式子,故#的前一位只能是数字或者右括号。
*
* 分为以下几种:数字,算数符(+ - * /),左括号,右括号,点,清零符
* 数字任何时候均可进行输入
* judge1用于运算符的判断,运算符之前只能有数字,括号
* judge2用于点的判断。
* judgeleft用于左括号的判定,另外只有在输入左括号之后才能输入右括号,另外输完左括号之后还能再输,可以连续输入两个左括号
* judgeleftright 用于右括号的判定,另外输完右括号之后还能再输,可以连续输入两个右括号
* 其中还有一些情况没有完全避免
*
*/
public boolean judge1=false;
public boolean judge2=true;
public boolean judgeleft=true;
public boolean judgeleftright=false;
public void launch() {
TextField tf=new TextField(30);
tf.setSize(300, 100);
tf.setBackground(Color.WHITE);
tf.setEditable(true);
JFrame interface1=new JFrame();
interface1.setTitle("按#=得结果");
interface1. setLayout(new BorderLayout());//创建BorderLayout布局(几行几列)
interface1.add(tf,BorderLayout.NORTH);
Panel p=new Panel(new GridLayout(5,4,5,5));//将面板设置成5行四列
for(int i=0;i<10;i++)
{
Button bn=new Button(""+i);
bn.setActionCommand("数字");//数字为一类
p.add(bn);
bn.addActionListener(new ActionEventDemo(interface1,tf));
}
Button D=new Button(".");
D.setActionCommand("点");
p.add(D);
D.addActionListener(new ActionEventDemo(interface1,tf));//点为一类
Button add=new Button("+");
add.setActionCommand("算数符");
p.add(add);
add.addActionListener(new ActionEventDemo(interface1,tf));
Button sub=new Button("-");
sub.setActionCommand("算数符");
p.add(sub);
sub.addActionListener(new ActionEventDemo(interface1,tf));
Button mult=new Button("*");
mult.setActionCommand("算数符");
p.add(mult);
mult.addActionListener(new ActionEventDemo(interface1,tf));
Button div=new Button("/");
div.setActionCommand("算数符");
p.add(div);
div.addActionListener(new ActionEventDemo(interface1,tf));//运算符为一类
Button left=new Button("(");
left.setActionCommand("左括号");
p.add(left);
left.addActionListener(new ActionEventDemo(interface1,tf));
Button right=new Button(")");
right.setActionCommand("右括号");
p.add(right);
right.addActionListener(new ActionEventDemo(interface1,tf));//括号为一类
Button end=new Button("#");
end.setActionCommand("结束符");
p.add(end);
end.addActionListener(new ActionEventDemo(interface1,tf));//结束符
Button result=new Button("==");
result.setActionCommand("结果符");
p.add(result);
result.addActionListener(new ActionEventDemo(interface1,tf));//按完结束符才能按结果符
Button zero =new Button("清零");
zero.setActionCommand("清零符");
p.add(zero);
zero.addActionListener(new ActionEventDemo(interface1,tf));
interface1.add(p,BorderLayout.CENTER);
interface1.setBounds(300,300,400,400);
interface1.setBackground(Color.black);
interface1. setVisible(true);
interface1.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(-1);
}
}
);
}
class ActionEventDemo implements ActionListener {
JFrame interface1=new JFrame();
TextField tf=new TextField();
ActionEventDemo(JFrame interface1,TextField tf){
this.interface1=interface1;
this.tf=tf;
}
public void actionPerformed(ActionEvent e) {
String strAc=e.getActionCommand();//*得到按钮实际命令。
Button bn=(Button)e.getSource();
String strLb=bn.getLabel();//得到按钮标签
if(strAc.equals("数字")) {
tf.setText(tf.getText()+strLb);
judge1=true;//输入数字之后就可以输算数符+ - * /了
end=true;//可以上输入结束符了,#符号之前只能是数字或者右括号
judgeleft=true;
}
else if(strAc.equals("算数符")&&judge1) {//运算符是一种
tf.setText(tf.getText()+strLb);
judge1=false;
judge2=true;
end=false;
judgeleft=true;
}
else if(strAc.equals("左括号")&&judgeleft) {//左括号是一种
tf.setText(tf.getText()+strLb);
judgeleftright=true;//可以输入右括号了
end=false;//#符号之前只能是数字或者右括号
}
else if(strAc.equals("右括号")&&judgeleftright) {//右括号是一种
tf.setText(tf.getText()+strLb);
//judgeleftright=false;
judgeleft=true;
end=true;
}
else if(strAc.equals("点")&&judge2) {//点是一种
tf.setText(tf.getText()+strLb);
judge2=false;
judgeleft=false;
end=false;
}
else if(strAc.equals("清零符")) {
tf.setText("");
//boolean变量全部赋成初值
result=false;//输入#之后result变为真,此时可以计算结果了,用于判断能否进行计算。
end=false;//前面有内容的时候才将其变为true,且输入#之后什么都不能输入了。
judge1=false;
judge2=true;
judgeleft=true;
judgeleftright=false;
}
else if(strAc.equals("结束符")&&end) {
tf.setText(tf.getText()+strLb);
result=true;
//什么都没法输入了,表示已经结束运算
end=false;
judge1=false;
judge2=false;
judgeleft=false;
judgeleftright=false;
}
else if(strAc.equals("结果符")&&result) {
String string=tf.getText();//得到结果符,获得TextField标签上内容字符串
MyCaculate caculate=new MyCaculate ();//形成计算的类的对象
double end1=caculate.caculate(tf.getText());//通过caculate方法得到计算结果end1
BigDecimal bg = new BigDecimal(end1);
double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
tf.setText(String.valueOf(f1)+"");
}
}
}
}
package Caculator;
import java.util.Stack;
/**
* 利用栈,进行四则运算的类
* 用两个栈来实现算符优先,一个栈用来保存需要计算的数据numStack,一个用来保存计算优先符priStack
*
* 基本算法实现思路为:用当前取得的运算符与priStack栈顶运算符比较优先级:若高于,则因为会先运算,放入栈顶;
* 若等于,因为出现在后面,所以会后计算,所以栈顶元素出栈,取出操作数运算;
* 若小于,则同理,取出栈顶元素运算,将结果入操作数栈。各个优先级'(' > '*' = '/' > '+' = '-' > ')'
*
*/
public class MyCaculate {
Stack<Double> numStack = new Stack<Double>();;// 操作数栈
Stack<Character> priStack = new Stack<Character>();// 操作符栈 //放在最前面,在方法中用不了
public double caculate(String numStr1) {
String numStr=numStr1.substring(0, numStr1.length()-1);//由于设置原因GUI界面传入的字符串最后一个字符为#,把它去掉,不去掉也行,那就把#作为结束符
if (numStr.length() > 1 && !"=".equals(numStr.charAt(numStr.length() - 1) )) {
numStr += "=";
//=作为结束符
}
StringBuffer temp=new StringBuffer();//为提高效率,临时存放字符
int i=0;
for(i=0;i<numStr.length();i++) {//大循环
char ch=numStr.charAt(i);
if(isNumber(ch)) temp.append(ch);
else {
//转换成String类型
if(!"".equals(temp.toString())) {//它是符号了说明符号前面的数字切割完毕
double num=Double.parseDouble(temp.toString());
numStack.push(num);
temp.delete(0, temp.length());//temp存放临时结果,放入栈中.
}
// 用当前取得的运算符与栈顶运算符比较优先级:若高于,则因为会先运算,放入栈顶;若等于,因为出现在后面,所以会后计算,所以栈顶元素出栈,取出操作数运算;
// 若小于,则同理,取出栈顶元素运算,将结果入操作数栈。
// 判断当前运算符与栈顶元素优先级,取出元素,进行计算(因为优先级可能小于栈顶元素,还小于第二个元素等等,需要用循环判断)
while(!compare(ch)&&!priStack.empty()) {//不如栈顶元素优先级高,那么我们将栈顶运算符取出,进行运算即可。
double b=numStack.pop();
double a=numStack.pop();
double c;
switch((char)priStack.pop()) {
case '+':c=a+b; numStack.push(c); break;
case '-':c=a-b; numStack.push(c);break;
case '*':c=a*b;numStack.push(c);break;
case '/':c=a/b;numStack.push(c);break;
}
}
if(ch!='=') {priStack.push(new Character(ch));
if(ch==')') {// 当栈顶为'(',而当前元素为')'时,则是括号内以算完,去掉括号
priStack.pop();
priStack.pop();
}
}
}
}
return numStack.pop();
}
private boolean isNumber(char num) {
if (num >= '0' && num <= '9'||num=='.') return true;
else return false;//有了这个方法就不用判断他是否是数字还是符号了,如果是.也把它当作数字来看待
}
/**
* 比较当前操作符与栈顶元素操作符优先级,如果比栈顶元素优先级高,即最后算,则返回true,否则返回false
*
* str 需要进行比较的字符
* 比较结果 true代表比栈顶元素优先级高,false代表比栈顶元素优先级低 ,true表示后算
*/
public boolean compare(char str) {
if (priStack.empty()) {
// 当为空时,显然 当前优先级最低,返回高
return true;
}
char last = (char) priStack.lastElement();
// 如果栈顶为'('显然,优先级最低,')'不可能为栈顶。
if (last == '(') { //'('为栈顶无法放入其他符号,直到遇到右括号出栈,入栈
return true;
}
switch (str) {
// '+-'为最低,一直返回false,先算,出栈
case '+':
return false;
case '-':
return false;
case '(':
// '('优先级最高,显然返回true,最后算,入栈
return true;
case '=':
return false;// 结束符 ,全部出栈
case ')':
// ')'优先级最低,前面必有左括号,出栈
return false;
case '*': {
if (last == '+' || last == '-') //入栈
return true;
else
return false; //栈顶元素出栈
}
case '/': {
if (last == '+' || last == '-')
return true; //入栈
else
return false; //栈顶元素出栈
}
}
return true;
}
//public static void main(String []args) {
// MyCaculate operate = new MyCaculate();
// double t = operate.caculate("((9.8-3.5)/(25.1-25.3)+7)*4#");
// System.out.println(t);
// }//用于测试数据
}