实验一 简单计算器的实现

基于Java Swing/Awt的UI界面

目录

基于Java Swing/Awt的UI界面

1.界面设计

2.功能描述

3.界面浏览

4.实现功能

5.效果:

6.代码实现

(1)定义运算优先级

(2)中缀表达式到后缀表达式的转化 

 (2)后缀表达式的计算

(3)界面布局: 

 (4)计算过程处理(以等号=为表达式结束标志)

7.对特殊按钮的处理

(1)当前按钮是‘del’:

(2)当前按钮是‘clr’:

8.其他运算符或者数字时:

9.主测试类:

10.不足之处:


1.界面设计

        界面由24个按钮和1个线型编辑器、1个历史文本框构成,仿照小米手机软件中简单计算器,整体配色为黑、白、蓝色,背景为白色,按钮为蓝色,边框以及表达符号为黑色;

2.功能描述

del:删去表达式的一个字符,退格

clr:清楚表达式内容

!:求阶乘符号

^:求指数幂

其他运算符和操作数:输入对应的字符

3.界面浏览

4.实现功能

1,加减乘除可配合括号正常计算

2,表达式出现不符合语法时,会在提示栏自动报错

3, 实现了取余、指数、阶乘、平方等功能

4,实现小数点后八位的精确计算

5,实现按钮和键盘对计算器的同时监听控制

5.效果:

                        

 6.代码实现

(1)定义运算优先级

static private int Precedence(char op) {
        switch (op) {
            case '+':
            case '-':
                return 1; // 定义加减运算的优先级为1
            case '*':
            case '/':
            case '%':
                return 2; // 定义乘除与取余运算的优先级为2
            case '^':
                return 3; // 定义次方运算的优先级为3
            case '!':
                return 4; // 定义阶乘运算的优先级为4
            case '(':
            case '=':
            default:
                return 0; // 定义在栈中的左括号和栈底字符的优先级为0
        }
    }

(2)中缀表达式到后缀表达式的转化 

 /**
     * 中缀表达式转换后缀表达式
     * @param str 中缀表达式字符串(要求以=结尾)
     * @return 后缀表达式的字符串形式
     * @throws Exception 中缀表达式存在错误
     */
    static private String toSuffix(String str) throws Exception {
        String d=str;
        StringBuffer strBuf = new StringBuffer();// 存储后缀表达式
        Stack<Character> stack = new Stack<Character>();// 字符栈,用于处理运算符
        stack.push('=');// 压入栈底字符
        int i = 0;// 中缀式字符串迭代器
        if (str == null || str.equals("") || str.equals("="))
            throw new Exception("表达式不能为空");
        char ch = str.charAt(i);// 临时字符处理
        if (ch == '.')
            throw new Exception("表达式格式不规范(不能以“.”开头)");
        if (str.charAt(str.length() - 1) != '=')
            throw new Exception("表达式格式不规范(不以“=”结尾)");
        if (ch == '-' || ch == '+')
            strBuf.append("0 ");//正负号首位补零
        while (ch != '=') {
            if (ch == ' ')
                ch = str.charAt(++i);// 读取下一个字符(忽略空格)
            else if (ch == '(') {
                stack.push('(');// 如果是左括号将其压入栈
                ch = str.charAt(++i);
                if (ch == '-' || ch == '+')
                    strBuf.append("0 ");//正负号补零
            } else if (ch == ')') {//查看前面是否有左括号
                while (stack.peek() != '(') {
                    if (stack.peek() == '=')//stack.peek是查看栈顶的元素但不移除它。pop方法会移除掉栈顶元素
                        throw new Exception("表达式括号不匹配,缺少“(”");
                    strBuf.append(stack.pop());//把栈顶元素追加到字符串strBuf后
                }
                stack.pop();
                ch = str.charAt(++i);
            } else if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^' || ch == '!' || ch == '%') {
                char w = stack.peek();// 临时读取栈中的运算符
                // 将现在的运算符和栈中的运算符进行优先级比较
                while (Precedence(w) >= Precedence(ch)) {
                    strBuf.append(w);//把运算符w追加到字符串strBuf后
                    stack.pop();//弹出该运算符,进行下一个运算符优先级的比较
                    w = stack.peek();
                }
                stack.push(ch);//将运算符ch压入栈
                ch = str.charAt(++i);
            } else {
                // 直接将数字和小数点加到后缀式中,把小数点的优先级设定成和数字一样
                if (!((ch >= '0' && ch <= '9') || ch == '.'))
                    throw new Exception("表达式出现非法符号");
                while ((ch >= '0' && ch <= '9') || ch == '.') {
                    strBuf.append(ch);//把数字ch追加到字符串strBuf后
                    ch = str.charAt(++i);
                }
                strBuf.append(' ');//把空格追加到字符串strBuf后
            }
        }
        ch = stack.pop();
        while (ch != '=') {//检查括号的完整性
            if (ch == '(')
                throw new Exception("表达式括号不匹配,缺少“)”");
            else {
                strBuf.append(ch);
                ch = stack.pop();
            }
        }
        strBuf.append('=');//把等于追加到字符串strBuf后
        return strBuf.toString();//返回后缀表达式strBuf
    }

 (2)后缀表达式的计算

 /**
     * 计算后缀表达式
     * @param str 后缀表达式的字符串形式
     * @return 高精度浮点数
     * 如果计算过程中出现循环小数则取至小数点后15位
     * @throws Exception 计算过程出现错误
     */
    static private BigDecimal runSuffix(String str) throws Exception {
        System.out.println(str);//输入后缀表达式str
        Stack<BigDecimal> stack = new Stack<BigDecimal>();//进行大数计算的栈
        int i = 0;//设置后缀表达式迭代器
        BigDecimal num1, num2;//临时大数变量
        StringBuffer strBuf;//
        while (str.charAt(i) != '=') {
            strBuf = new StringBuffer();
            if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
                while ((str.charAt(i) >= '0' && str.charAt(i) <= '9') || str.charAt(i) == '.')
                    strBuf.append(str.charAt(i++));//形成数字
                try {//Java的异常处理机制
                    stack.push(new BigDecimal(strBuf.toString()));
                } catch (Exception e) {
                    throw new Exception("表达式计算数出错");
                }
            } else if (str.charAt(i) == ' ')
                i++;//忽略空格
            else if (str.charAt(i) == '+') {
                if (stack.size() < 2)
                    throw new Exception("表达式缺少计算数");
                num1 = stack.pop();
                num2 = stack.pop();
                stack.push(num1.add(num2));//加法运算
                i++;
            } else if (str.charAt(i) == '-') {
                if (stack.size() < 2)
                    throw new Exception("表达式缺少计算数");
                num1 = stack.pop();
                num2 = stack.pop();
                stack.push(num2.subtract(num1));//减法运算
                i++;
            } else if (str.charAt(i) == '*') {
                if (stack.size() < 2)
                    throw new Exception("表达式缺少计算数");
                num1 = stack.pop();
                num2 = stack.pop();
                stack.push(num1.multiply(num2));//乘法运算
                i++;
            } else if (str.charAt(i) == '%') {
                if (stack.size() < 2)
                    throw new Exception("表达式缺少计算数");
                num1 = stack.pop();
                num2 = stack.pop();
                try {
                    BigInteger numT1 = num1.toBigIntegerExact();
                    BigInteger numT2 = num2.toBigIntegerExact();
                    stack.push(new BigDecimal(numT2.remainder(numT1).toString()));//取余运算
                } catch (ArithmeticException e) {
                    throw new Exception("参与取余运算的数只能是整数,且除数不能为0");
                } catch (Exception e) {
                    throw new Exception("表达式取余运算出现错误");
                }
                i++;
            } else if (str.charAt(i) == '^') {
                if (stack.size() < 2)
                    throw new Exception("表达式缺少计算数");
                num1 = stack.pop();
                num2 = stack.pop();
                try {
                    BigInteger numT = num1.toBigIntegerExact();
                    if (numT.compareTo(new BigInteger("0")) == numT.compareTo(new BigInteger("999999999")))
                        throw new ArithmeticException();
                    stack.push(num2.pow(numT.intValue()));//次方运算
                } catch (ArithmeticException e) {
                    throw new Exception("幂的范围只能是0到9999之间,且只能是整数");
                } catch (Exception e) {
                    throw new Exception("幂运算出现错误");
                }
                i++;
            } else if (str.charAt(i) == '!') {
                if (stack.size() < 1)
                    throw new Exception("表达式缺少计算数");
                num1 = stack.pop();
                try {
                    BigInteger numT = num1.toBigIntegerExact();
                    if (numT.compareTo(new BigInteger("0")) == numT.compareTo(new BigInteger("9999")))
                        throw new ArithmeticException();
                    int count = numT.intValue();
                    num2 = new BigDecimal("1");
                    while (count > 0)
                        num2 = num2.multiply(new BigDecimal(count--));//阶乘运算
                    stack.push(num2);
                } catch (ArithmeticException e) {
                    throw new Exception("阶乘的范围只能是0到9999之间,且只能是整数");
                } catch (Exception e) {
                    throw new Exception("阶乘运算出现错误");
                }
                i++;
            } else if (str.charAt(i) == '/') {
                if (stack.size() < 2)
                    throw new Exception("表达式缺少计算数");
                num1 = stack.pop();
                num2 = stack.pop();
                try {
                    stack.push(num2.divide(num1));//除法运算
                } catch (ArithmeticException e) {
                    try {
                        //出现循环小数将其处理为小数点只保留8位
                        stack.push(num2.divide(num1, 8, RoundingMode.HALF_UP));
                    } catch (ArithmeticException e2) {
                        throw new Exception("除法运算出现错误(可能是0作了除数)");
                    }
                }
                i++;
            }
        }
        if (stack.size() != 1)
            throw new Exception("表达式缺少运算符");
        return stack.pop();
    }

(3)界面布局: 

public Calculator() {
this.setTitle("Java简单计算器");//定义窗口标题
        this.setSize(560, 300);//窗口大小
        this.setResizable(false);//禁止用户调整大小
        StringTokenizer strT = new StringTokenizer(str, " ");//将按钮字符集按空格分隔
        Container c = this.getContentPane();//获取根容器
        showResult.setBorder(new LineBorder(Color.BLACK, 1));//设置文本区域边框
        showResult.setLineWrap(true);//文本区域可自动换行
        showResult.setEditable(false);//文本区域不可编辑
        showResult.addKeyListener(this);//文本区域增加键盘事件监听
        showUser = new JScrollPane(showResult);//为文本区域加上拖动条
        History.setBorder(new LineBorder(Color.BLACK, 1));//设置文本区域边框
        History.setLineWrap(true);//文本区域可自动换行
        History.setEditable(false);//文本区域不可编辑
        History.addKeyListener(this);//文本区域增加键盘事件监听
        historyUser = new JScrollPane(historyUser );//为文本区域加上拖动条
        label.setBounds(30, 15, 100, 20);//设置标签位置及大小
        this.add(label);// 新建“历史记录”标签
        History.setLineWrap(true);//自动换行
        History.setWrapStyleWord(true);
        History.setSelectedTextColor(Color.blue);
        westPanel.add(showUser, BorderLayout.CENTER);
        westPanel.add(tips, BorderLayout.SOUTH);
        westPanel.add(label, BorderLayout.NORTH);
        westPanel.add(History,BorderLayout.NORTH);
        eastPanel.setLayout(new GridLayout(6, 4, 2, 2));//布局
}

 (4)计算过程处理(以等号=为表达式结束标志)

private void run() {
        List<String> list=new ArrayList<>();
 //     Iterator<String> it=list.iterator();
        StringBuffer strBuff= strBuf;
        strBuff.append('=');//表达式规范化以=结尾
        try {
            //计算并且显示
            long beforeTime = System.currentTimeMillis();
            String strTemp;
            showResult.setText(strBuff.append(strTemp = (CalculatorEngine.run(strBuff.toString())).toString()).toString());
            list.add(strBuff.toString());
            int length = list.size();
            int i=length;
            StringBuffer d=null;
            while(i--!=0)
                History.setText(list.get(i));//在历史记录框里显示计算表达式及结果

            //History.setText(strBuff.toString());
            strBuf.setLength(0);//表达式字符串清空
            strBuf.append(strTemp);//新的计算保存原来的结果
            //History.setText(strBuf+strTemp);//在历史记录框里显示计算表达式及结果
            tips.setText("计算已完成");
        } catch (Exception ex) {
            if (ex.getMessage() == null || ex.getMessage().equals(""))
                tips.setText("发生未知错误");
            else
                tips.setText(ex.getMessage());//将错误输出到提示标签上
        }
    }

 7.对特殊按钮的处理

(1)当前按钮是‘del’:

if (e.getSource() == button[21]) {
            strBuf.setLength(strBuf.length() > 0 ? strBuf.length() - 1 : 0);//删除一个字符,del
            showResult.setText(strBuf.toString());//显示

(2)当前按钮是‘clr’:

if (e.getSource() == button[22]) {
            strBuf.setLength(0);//清空,clr
            showResult.setText(strBuf.toString());//显示
if (e.getSource() == button[23]) {

            run();//点击=则计算

 8.其他运算符或者数字时:

if ((e.getKeyChar() >= '0' && e.getKeyChar() <= '9') || e.getKeyChar() == '.' ||
                e.getKeyChar() == '+' || e.getKeyChar() == '-' || e.getKeyChar() == '*' ||
                e.getKeyChar() == '/' || e.getKeyChar() == '(' || e.getKeyChar() == ')' ||
                e.getKeyChar() == '^' || e.getKeyChar() == '!' || e.getKeyChar() == '%' || e.getKeyChar() == ' ') {
            //计算表达式的形成
            showResult.setText(strBuf.append(e.getKeyChar()).toString());

9.主测试类:

class test {
    public static void main(String[] args) {
        Calculator cFrame = new Calculator();
        cFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        cFrame.setVisible(true);
        //JOptionPane.showMessageDialog(null, "请注意正确使用java表达式计算器!\n");
    }
}

 10.不足之处:

1,历史记录文本框功能不完善,不能实现历史记录的回调

2,显示栏中输入错误表达式,只能在提示栏显示错误。

     例如:可以输入多个小数点,此时提示栏仍然会报错,但是不能限制同时输入多个小数点

代码见:实验一:简单计算器的实现代码_qq_45929513的博客-CSDN博客

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值