计算器GUI程序

这篇博客介绍了如何使用Java语言设计一个支持加、减、乘、除、求余、括号运算符及SQR和ABS函数的GUI计算器。程序包括了表达式的合法性检查、中缀表达式转后缀表达式以及对后缀表达式的计算。博主采用了JavaSwing创建用户界面,并实现了大数和浮点数运算。文章提供了部分关键代码片段,完整代码已上传到gitee。
摘要由CSDN通过智能技术生成

模拟计算器

  1. 问题描述
    设计一个模拟计算器的程序,要求能对包含加、减、乘、除、求余、括号运算符及SQR和ABS函数的任意整型表达式进行求解。
  2. 设计要求
    (1)要检查相关运算的限制条件,并对错误的条件产生报警。
    (2)有用户图形界面。

数据结构课程设计,我选用的是Java语言来实现一个GUI计算器程序,图形界面使用Java Swing进行开发,实现了基本运算,以及绝对值、开方、平方,支持浮点数以及大数运算。 涉及到的知识点有将中缀表达式转换为后缀表达式并进行计算,同时能够检查表达式是否合法。

设计思路:

在这里插入图片描述

用户交互界面

在这里插入图片描述

表达式的合法判定

import java.util.Stack;

public class CheckExpression {
    // 判断是否是合法算术表达式
    public boolean isTrueExpression(String expression) {
        // 如果一开始就是点(.)肯定就不是合法的表达式  合法的算术表达式含有数字、小数点、括号、普通运算符
        if ("".equals(expression) || isOperator(expression.charAt(0)) || isOperator(expression.charAt(expression.length() - 1)) || isPoint(expression.charAt(0)) || isPoint(expression.charAt(expression.length() - 1))) {
            return false;
        } else {
            
            // 控制括号成对
            Stack<Character> stack = new Stack<>();
            
            // 循环判断表达式的每一个字符是符合法
            int i = 0;
            int leftCount = 0;// 记录 ( 的数量
            int rightCount = 0;// 记录 ) 的数量
            
            while (i < expression.length()) {
                char ch = expression.charAt(i);
                // 如果此字符不是数字、普通运算符、特殊运算符、小数点、括号、空格(习惯分开 比如:2 + 4) 那么就是不合法
                if (isNumber(ch) || isOperator(ch) || isSpecialOperator(ch) || isPoint(ch) || isBracket(ch) || ch == ' ') {
                    //如果此字符是空格  那么如果他的前一个或后一个是小数点、前后都是数字或者元素字符,那么这个表达式就是不合法,
                    // 不过由于本计算器是用户点击按钮进行输入,所以不会出现多出多余空格的错误
                    // 此字符前后可能有多个空格,调用方法得到此字符的前/后一个的有效字符
                    int pre = getPreIndexOfNotBlankSpace(expression, i);
                    int next = getNextIndexOfNotBlankSpace(expression, i);
                    
                    if (ch == ' ') {
                        if (isPoint(expression.charAt(pre)) || isPoint(expression.charAt(next)) || (isNumber(expression.charAt(pre))) && isNumber(expression.charAt(next)) || (isOperator(expression.charAt(pre))) && isOperator(expression.charAt(next))) {
                            return false;
                        }
                    }
                    
                    // 如果是左括号( 那么下一个有效字符必须不能是小数点或者*、/、)、%
                    if (ch == '(') {
                        leftCount++;
                        if (isPoint(expression.charAt(next)) || expression.charAt(next) == '*' || expression.charAt(next) == '/' || expression.charAt(next) == ')' || expression.charAt(next) == '%') {
                            return false;
                        }
                        // 入栈
                        stack.push(ch);
                    }
                    // 如果是) 此时栈空则说明不合法 否则弹出一个(   )后面只可以是运算符或者)
                    if (ch == ')') {
                        rightCount++;
                        if (stack.empty() || (!isOperator(expression.charAt(next)) && expression.charAt(next) != ')')) {
                            return false;
                        } else {
                            stack.pop();
                        }
                    }
                    
                    // 如果是除号 后一个数是0就不合法 除数不能是0
                    if (ch == '/') {
                        if (expression.charAt(next) == '0') {
                            return false;
                        }
                    }
                    
                    // 如果是运算符,前一个或后一个不能是小数点、操作符
                    if (isOperator(ch) || isSpecialOperator(ch)) {
                        if (isPoint(expression.charAt(pre)) || isPoint(expression.charAt(next)) || expression.charAt(next) == ')' || isOperator(expression.charAt(next))) {
                            return false;
                        }
                    }
                    
                    // 如果是小数点,前后都必须是数字
                    if (isPoint(ch)) {
                        if (!isNumber(expression.charAt(pre)) || !isNumber(expression.charAt(next))) {
                            return false;
                        }
                    }
                    i++;
                } else {
                    return false;
                }
            }
            
            // 如果字符都合法最后判断括号是否成对:即(数量 和 )括号数量是否相等
            if (leftCount != rightCount) {
                // 说明括号不是成对出现
                return false;
            }
        }
        return true;
    }
    
    // 获取后一个有效字符下标
    public static int getPreIndexOfNotBlankSpace(String expression, int i) {
        // 如果下表是最后一个字符下标那么就返回最后一个字符下标
        if (i == 0) {
            return 0;
        } else if (i < 0 || i >= expression.length()) {
            throw new RuntimeException("error");
        } else {
            i--;
            while (expression.charAt(i) == ' ') {
                i--;
            }
            return i;
        }
    }
    
    // 获取前一个有效字符的下标
    public static int getNextIndexOfNotBlankSpace(String expression, int i) {
        // 如果下标为0 那么前一个有效字符就是0
        if (i == expression.length() - 1) {
            return expression.length() - 1;
        } else if (i < 0 || i >= expression.length()) {
            throw new RuntimeException("error");
        } else {
            i++;
            while (expression.charAt(i) == ' ') {
                i++;
            }
            return i;
        }
    }
    
    
    // 判断这个字符是不是数字
    public static boolean isNumber(char ch) {
        if (ch >= '0' && ch <= '9') {
            return true;
        } else {
            return false;
        }
    }
    
    // 判断这个字符是不是普通运算符
    public static boolean isOperator(char ch) {
        if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%') {
            return true;
        } else {
            return false;
        }
    }
    // 判断这个字符是不是普通运算符
    public static boolean isSpecialOperator(char ch) {
        if (ch == 'A' || ch == 'S' || ch == 'P') {
            return true;
        } else {
            return false;
        }
    }
    
    // 判断这个字符是不是小数点
    public static boolean isPoint(char ch) {
        return ch == '.';
    }
    
    // 判断这个字符是不是括号
    public static boolean isBracket(char ch) {
        return ch == '(' || ch == ')';
    }
}

将中缀表达式转换为后缀表达式

//中缀表达式转后缀表达式
    //比如输入为1+5*7,转为后缀表达式为157*+
    private void Infix2Postfix() {
        // 依次扫描表达式eq1
        for(int i = 0;i < eq1.size();i++) {
            if(prio.get(eq1.get(i)) != null) { //对运算符进行处理
                String c = eq1.get(i);
                if(stk.empty() || c.equals("(")) { //如果栈为空或者是左括号,直接入栈。为什么左括号也要直接入栈?考虑到括号嵌套问题,如6+((1+2)*3+4)*5
                    stk.push(c);
                } else if(c.equals(")")) { //遇到右括号,将栈顶元素一直出栈直到遇到左括号为止,并将该左括号出栈(右括号不入栈)
                    while(!stk.peek().equals("(")) {
                        //只要栈顶元素不为左括号,就将该运算符出栈并添加到列表中
                        eq2.add(stk.pop());
                    }
                    stk.pop(); //将左括号出栈
                } else if(prio.get(c) > prio.get(stk.peek())) {
                    //如果当前运算符优先级高于栈顶运算符优先级,直接入栈
                    stk.push(c);
                } else { //当前运算符优先级低于或等于栈顶运算符优先级,分四种情况
                    while(!stk.empty() && !stk.peek().equals("(") && prio.get(stk.peek()) >= prio.get(c)) {
                        eq2.add(stk.pop());
                    }
                    // 之后再把当前运算符入栈
                    stk.push(c);
                }
            } else { //对参数数据进行处理,参数直接添加进列表
                eq2.add(eq1.get(i));
            }
        }
        // 按以上方法处理完所有的字符后,再将栈中所有运算符依次弹出,并加入后缀表达式
        while(!stk.empty()){
            eq2.add(stk.pop());
        }
        System.out.println("中缀表达式eq1: " + eq1);
        System.out.println("后缀表达式eq2: " + eq2);
    }

对后缀表达式进行计算

//对后缀表达式计算
    private String postfixCalculate() {
        BigDecimal p1,p2;
        BigDecimal p3 = new BigDecimal("0");

        for(int i = 0;i < eq2.size();i++){
            if(prio.get(eq2.get(i)) == null){ //对参数进行处理
                stk.push(eq2.get(i)); //参数直接入栈
            } else { //对运算符进行处理
                String c = eq2.get(i);
                // 如果是S或者A运算需要单独处理
                if (c.equals("A")) {
                    // 绝对值运算
                    p3 = new BigDecimal(stk.pop()).abs();
                    stk.push(p3.toString());
                } else if (c.equals("S")) {
                    // 开方运算
                    p3 = new BigDecimal(Math.sqrt(Double.valueOf(stk.pop())));
                    stk.push(p3.toString());
                } else if (c.equals("P")) {
                    // 平方运算
                    p3 = new BigDecimal(Math.pow(Double.valueOf(stk.pop()), 2.0));
                    stk.push(p3.toString());
                } else {
                    p1 = new BigDecimal(stk.pop());
                    p2 = new BigDecimal(stk.pop());

                    switch(c){
                        case "+":p3 = p2.add(p1);break;

                        case "-":p3 = p2.subtract(p1);break;

                        case "*":p3 = p2.multiply(p1);break;

                        // 除法精确到小数点后第18位,并四舍五入
                        case "/": p3 = p2.divide(p1, RoundingMode.HALF_UP);break;
                        //case "/": p3 = new BigDecimal((p2.doubleValue()/p1.doubleValue()));

                        case "%":p3 = p2.remainder(p1);break;

                        default:p3=BigDecimal.ZERO;break;
                    }
                    stk.push(p3.toString());
                }
            }
        }
        return stk.pop();
    }

**注:**以上只是部分代码,完整代码我上传到了gitee保管,calculator,点击即可访问。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值