Java之混合计算器的实现

2022-07-27,,

写这个计算器一来是之前学了Java的GUI编程,学的目的本来是想写贪吃蛇的,最后因为素材不足没有写成,本以为白学了GUI编程,最近老师布置了一个关于GUI编程的题写一个混合计算器的界面,一开始看到后感觉很懵逼,但当自己一点点写起来之后发现也还行,下面的计算器的实现我花了很久才写出来。现拿出来供大家参考,可能还存在一定的问题,如果哪位大佬发现可以提出来,本人还是一位菜鸟,欢迎大佬找问题。下面是我的计算器的界面以及源码。

package Calcultor;

public class Main {
    public static void main(String[] args) {
        new CalculatorJFrame();
    }
}
//author:sd 唐务强
package Calcultor;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class CalculatorJFrame extends JFrame implements ActionListener {
    public CalculatorJFrame() {
        init();
    }
    //定义按钮
    JButton button0;
    JButton button1;
    JButton button2;
    JButton button3;
    JButton button4;
    JButton button5;
    JButton button6;
    JButton button7;
    JButton button8;
    JButton button9;
    JButton buttonRight;
    JButton buttonLeft;
    JButton buttonC;
    JButton buttonCE;
    JButton buttonEqual;
    JButton buttonPoint;
    JButton buttonReduce;
    JButton buttonAdd;
    JButton buttonRide;
    JButton buttonBack;
    JButton buttonSquare;
    JButton buttonRadical;
    JButton buttonExcept;
    JTextField inputText;
    JTextField outputText;
    //初始化界面
    //author:唐务强
    public void init() {
        //定义标题
        JFrame frame = new JFrame("TWQ的计算器");
        frame.setLayout(null);
        frame.setBounds(800, 200, 500, 500);
        Font font = new Font("Courier new", Font.PLAIN, 20);
        //对于JFrame窗体需要用用一个容器来设置其背景颜色,如果直接设置背景颜色的话则不会成功
        Container container = frame.getContentPane();
        //将背景颜色设置为天蓝色
        container.setBackground(Color.CYAN);

        //放置按钮0
        button0 = new JButton("0");
        button0.setBounds(20, 400, 155, 45);//放置按钮位置
        button0.setFont(font);
        //button0.setBackground(Color.white);
        frame.add(button0);
        //放置按钮1
        button1 = new JButton("1");
        button1.setBounds(20, 320, 55, 45);
        button1.setFont(font);
        frame.add(button1);
        //放置按钮4
        button4 = new JButton("4");
        button4.setBounds(20, 240, 55, 45);
        button4.setFont(font);
        frame.add(button4);
        //放置按钮7
        button7 = new JButton("7");
        button7.setBounds(20, 160, 55, 45);
        button7.setFont(font);
        frame.add(button7);
        //放置左括号
        buttonLeft = new JButton("(");
        buttonLeft.setBounds(20, 80, 55, 45);
        buttonLeft.setFont(font);
        frame.add(buttonLeft);
        //放置右括号
        buttonRight = new JButton(")");
        buttonRight.setBounds(120, 80, 55, 45);
        buttonRight.setFont(font);
        frame.add(buttonRight);
        //放置8按钮
        button8 = new JButton("8");
        button8.setBounds(120, 160, 55, 45);
        button8.setFont(font);
        frame.add(button8);
        //放置按钮5
        button5 = new JButton("5");
        button5.setBounds(120, 240, 55, 45);
        button5.setFont(font);
        frame.add(button5);
        //放置按钮2
        button2 = new JButton("2");
        button2.setBounds(120, 320, 55, 45);
        button2.setFont(font);
        frame.add(button2);
        //放置按钮3
        button3 = new JButton("3");
        button3.setBounds(220, 320, 55, 45);
        button3.setFont(font);
        frame.add(button3);
        //放置按钮6
        button6 = new JButton("6");
        button6.setBounds(220, 240, 55, 45);
        button6.setFont(font);
        frame.add(button6);
        //放置按钮9
        button9 = new JButton("9");
        button9.setBounds(220, 160, 55, 45);
        button9.setFont(font);
        frame.add(button9);
        //放置清空所有按钮
        buttonC = new JButton("C");
        buttonC.setBounds(220, 80, 155, 45);
        buttonC.setFont(font);
        frame.add(buttonC);
        //放置根号按钮
        buttonRadical=new JButton("√");
        buttonRadical.setBounds(320, 160, 55, 35);
        buttonRadical.setFont(font);
        frame.add(buttonRadical);
        //放置求平方按钮
        buttonSquare=new JButton("x^2");
        buttonSquare.setBounds(320, 210, 55, 35);
        frame.add(buttonSquare);
        //放置除号
        buttonExcept = new JButton("/");
        buttonExcept.setBounds(320, 260, 55, 35);
        buttonExcept.setFont(font);
        frame.add(buttonExcept);
        //放置乘号
        buttonRide = new JButton("*");
        buttonRide.setBounds(320, 310, 55, 35);
        buttonRide.setFont(font);
        frame.add(buttonRide);
        //放置减号
        buttonReduce = new JButton("-");
        buttonReduce.setBounds(320, 360, 55, 35);
        buttonReduce.setFont(font);
        frame.add(buttonReduce);
        //放置加号
        buttonAdd = new JButton("+");
        buttonAdd.setBounds(320, 410, 55, 35);
        buttonAdd.setFont(font);
        frame.add(buttonAdd);
        //放置等号
        buttonEqual = new JButton("=");
        buttonEqual.setBounds(415, 340, 68, 105);
        buttonEqual.setFont(font);
        frame.add(buttonEqual);
        //放置清空当前输入按钮
        buttonCE = new JButton("CE");
        buttonCE.setBounds(415, 80, 68, 105);
        buttonCE.setFont(font);
        frame.add(buttonCE);
        //放置回退按钮
        buttonBack = new JButton("Back");
        buttonBack.setBounds(415, 210, 68, 105);
        //buttonBack.setFont(font);
        frame.add(buttonBack);
        //放置小数点按钮
        buttonPoint = new JButton(".");
        buttonPoint.setBounds(220, 400, 55, 45);
        buttonPoint.setFont(font);
        frame.add(buttonPoint);
        //放置输入文本框
        inputText = new JTextField("0");
        inputText.setBounds(20, 10, 460, 30);
        inputText.setFont(font);
        //放置输出文本框
        outputText = new JTextField();
        outputText.setBounds(20, 45, 460, 30);
        outputText.setFont(font);
        frame.add(outputText);
        //添加监听器
        button0.addActionListener(this);
        button1.addActionListener(this);
        button2.addActionListener(this);
        button3.addActionListener(this);
        button4.addActionListener(this);
        button5.addActionListener(this);
        button6.addActionListener(this);
        button7.addActionListener(this);
        button8.addActionListener(this);
        button9.addActionListener(this);
        buttonAdd.addActionListener(this);
        buttonPoint.addActionListener(this);
        buttonReduce.addActionListener(this);
        buttonExcept.addActionListener(this);
        buttonEqual.addActionListener(this);
        buttonRight.addActionListener(this);
        buttonLeft.addActionListener(this);
        buttonC.addActionListener(this);
        buttonCE.addActionListener(this);
        buttonExcept.addActionListener(this);
        buttonRide.addActionListener(this);
        buttonBack.addActionListener(this);
        buttonSquare.addActionListener(this);
        buttonRadical.addActionListener(this);
        frame.add(inputText);
        frame.setVisible(true);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }

    String s = null;
    //记录小数点是否出现,每次当前数字框中只能出现一个小数点
    int pointBook = 0;
    //记录等号是否出现,每次计算的总算式只能出现一个等号
    int equalBook = 0;
    //记录左括号的数量
    int LeftNum = 0;
    //记录右括号的数量
    int RightNum = 0;
    //
    @Override
    public void actionPerformed(ActionEvent e) {
        //按钮为0时
        if (e.getSource().equals(button0)) {
            s = inputText.getText();
            if (s.length() > 20) {

            } else if (s.equals("0") || equalBook == 1) {

            } else {
                inputText.setText(s + "0");
            }
        }
        //按钮为1时
        if (e.getSource().equals(button1)) {
            s = inputText.getText();
            if (s.length() > 20 || equalBook == 1) {

            } else if (s.equals("0") || s.equals("")) {
                inputText.setText("1");
            } else {
                inputText.setText(s + "1");
            }
        }
        //按钮为2时
        if (e.getSource().equals(button2)) {
            s = inputText.getText();
            //当在输入框中输入的长度大于20就停止输入了,也就是什么都不干,下面数字按钮也是同理就不在一一解释了
            if (s.length() > 20 || equalBook == 1) {

            } else if (s.equals("0") || s.equals("")) {//如果输入框为0或者为空则将输入框中的值设置为点击的按钮的值
                inputText.setText("2");
            } else {
                inputText.setText(s + "2");
            }
        }
        //按钮为3时
        if (e.getSource().equals(button3)) {
            s = inputText.getText();
            if (s.length() > 20 || equalBook == 1) {

            } else if (s.equals("0") || s.equals("")) {
                inputText.setText("3");
            } else {
                inputText.setText(s + "3");
            }
        }
        //按钮为4时
        if (e.getSource().equals(button4)) {
            s = inputText.getText();
            if (s.length() > 20 || equalBook == 1) {

            } else if (s.equals("0") || s.equals("")) {
                inputText.setText("4");
            } else {
                inputText.setText(s + "4");
            }
        }
        //按钮为5时
        if (e.getSource().equals(button5)) {
            s = inputText.getText();
            if (s.length() > 20 || equalBook == 1) {

            } else if (s.equals("0") || s.equals("")) {
                inputText.setText("5");
            } else {
                inputText.setText(s + "5");
            }
        }
        //按钮为6时
        if (e.getSource().equals(button6)) {
            s = inputText.getText();
            if (s.length() > 20 || equalBook == 1) {

            } else if (s.equals("0") || s.equals("")) {
                inputText.setText("6");
            } else {
                inputText.setText(s + "6");
            }
        }
        //按钮为7时
        if (e.getSource().equals(button7)) {
            s = inputText.getText();
            if (s.length() > 20 || equalBook == 1) {

            } else if (s.equals("0") || s.equals("")) {
                inputText.setText("7");
            } else {
                inputText.setText(s + "7");
            }
        }
        //按钮为8时
        if (e.getSource().equals(button8)) {
            s = inputText.getText();
            if (s.length() > 20 || equalBook == 1) {

            } else if (s.equals("0") || s.equals("")) {
                inputText.setText("8");
            } else {
                inputText.setText(s + "8");
            }
        }
        //按钮为9时
        if (e.getSource().equals(button9)) {
            s = inputText.getText();
            if (s.length() > 20 || equalBook == 1) {

            } else if (s.equals("0") || s.equals("")) {
                inputText.setText("9");
            } else {
                inputText.setText(s + "9");
            }
        }
        //按钮为小数点时
        if (e.getSource().equals(buttonPoint)) {
            s = inputText.getText();
            char s1[]=s.toCharArray();//将字符串转化为字符数组
            int len=s.length()-1;
            if (s.length() > 19 || equalBook == 1) {

            }
            //如果小数点没有出现,并且出现小数点时前面一个字符必须是数字才合法
            if (pointBook == 0&&Character.isDigit(s1[len])) {
                inputText.setText(s + ".");
                pointBook = 1;
            }
        }
        //按钮为加号时
        if (e.getSource().equals(buttonAdd)) {
            s = inputText.getText();
            char s1[] = s.toCharArray();
            int len1 = s.length() - 1;
            String S = outputText.getText();
            char s2[] = S.toCharArray();
            int len2 = S.length() - 1;
            //添加加号只能是在输入输出框不为空,或者输入框最后一个字符是数字或者输出框最后一个字符是左括号时才可以添加加号
            if ((len2 == -1 || s2[len2] != ')') && (s.equals("0") || s.equals("") || s1[len1] == '.')) {

            } else {
                inputText.setText("");
                outputText.setText(outputText.getText() + s + "+");
            }
        }
        //按钮为减号时
        if (e.getSource().equals(buttonReduce)) {
            s = inputText.getText();
            char s1[] = s.toCharArray();
            int len1 = s.length() - 1;
            String S = outputText.getText();
            char s2[] = S.toCharArray();
            int len2 = S.length() - 1;
			//添加减号与加号同理
            if ((len2 == -1 || s2[len2] != ')') && (s.equals("0") || s.equals("") || s1[len1] == '.')) {

            }else {
                inputText.setText("");
                outputText.setText(outputText.getText() + s + "-");
            }
        }
        //按钮为乘号时
        if (e.getSource().equals(buttonRide)) {
            s = inputText.getText();
            char s1[] = s.toCharArray();
            int len1 = s.length() - 1;
            String S = outputText.getText();
            char s2[] = S.toCharArray();
            int len2 = S.length() - 1;
            if ((len2 == -1 || s2[len2] != ')') && (s.equals("0") || s.equals("") || s1[len1] == '.')) {

            } else {
                inputText.setText("");
                outputText.setText(outputText.getText() + s + "*");
            }
        }
        //当点击求根号按钮时
        if(e.getSource().equals(buttonRadical)){
            s=inputText.getText();
            //将输入框中字符串转化为double类型的实数
            double a=Double.parseDouble(inputText.getText());
            a=Math.sqrt(a);//求a的开方
            inputText.setText(String.valueOf(a));//将数字a转化为字符串并放入输入框中
        }
        //当点击的是求平方按钮时
        if(e.getSource().equals(buttonSquare)){
            s=inputText.getText();
            double a=Double.parseDouble(inputText.getText());//上同
            a=Math.pow(a,2);
            inputText.setText(String.valueOf(a));
        }
        //按钮为除号时
        if (e.getSource().equals(buttonExcept)) {
            s = inputText.getText();
            char s1[] = s.toCharArray();
            int len1 = s.length() - 1;
            String S = outputText.getText();
            char s2[] = S.toCharArray();
            int len2 = S.length() - 1;
            if ((len2 == -1 || s2[len2] != ')') && (s.equals("0") || s.equals("") || s1[len1] == '.')) {

            } else {
                inputText.setText("");
                outputText.setText(outputText.getText() + s + "/");
            }
        }
        //按钮为左括号时
        if (e.getSource().equals(buttonLeft)) {
            //如果输的数字之后紧接着就输入一个左括号,那是没有意义的所以直接将当前输入的文本加进输出文本值中就可以了
            if (!inputText.getText().equals("0") && !inputText.getText().contentEquals("")) {
                outputText.setText(outputText.getText() + inputText.getText());
                inputText.setText("");
            }
            s = outputText.getText();
            char s1[] = s.toCharArray();
            int len = s.length() - 1;
            //如果当前字符输入框为空,或者前面是一个左括号时,或者前面是运算符时这时候可以添加一个左括号
            if (len == -1 ||s1[len]=='(' || s1[len] == '+' || s1[len] == '-' || s1[len] == '*' || s1[len] == '/') {
                outputText.setText(outputText.getText() + '(');//在原文本上再添加一个左括号即可
                LeftNum++;//左括号出现的次数加1
            }
        }
        //按钮为右括号时
        if (e.getSource().equals(buttonRight)) {
            s=inputText.getText();
            char s1[]=s.toCharArray();
            int len=s.length()-1;
            String S=outputText.getText();
            int len1=S.length()-1;
            char s2[]=S.toCharArray();
            //当前面一个字符是数字或者是右括号时可以添加右括号,但是前提是左括号的数量比右括号数量多
            //这地方有一个坑,困扰了我五六个小时,这个判断条件如果先判断输入框最后一个是否是一个数字然后
            //在判断输出框中最后一个字符是否是右括号,当时你输入((1+1)+(1+1)),点击最后一个括号的时候会报错
            //而且在输出框中也添加不上右括号,我想了很久不知道为什么,然后就无意之间交换了判断顺序,突然就对了,
            /*if ((Character.isDigit(s1[len])||s2[len1]==')')&&LeftNum>RightNum)这个判断条件是我一开始错的找了很久才发现*/
            if (s2[len1]==')'||(Character.isDigit(s1[len]))&&LeftNum>RightNum) {
                if(s2[len1]==')'&&s.equals(""))//如果输入框为空并且输出框最后一个字符为又括号时,这时可以添加右括号在输出框中
                    outputText.setText(outputText.getText()+')');
                else{
                    outputText.setText(outputText.getText() +inputText.getText()+ ')');
                    inputText.setText("");
                }
                RightNum++;
            }
        }
        //按钮为C时清空所有内容
        if (e.getSource().equals(buttonC)) {
            //当点击C之后清空输入输出框中文本,并将左括号右括号,等号,小数点的数量也要清空
            outputText.setText("");
            inputText.setText("0");
            LeftNum = 0;
            RightNum = 0;
            pointBook = 0;
            equalBook = 0;

        }
        //按钮为CE时清空当前输入内容
        if (e.getSource().equals(buttonCE)) {
            //将输入框中文本清空即可
            inputText.setText("0");
            pointBook = 0;
        }
        //按钮为Back时
        if (e.getSource().equals(buttonBack)) {
          
            s = inputText.getText();
            if (s.length() > 0) {
            //点击一次就将输入框中的字符删掉一个
                inputText.setText(s.substring(0, s.length() - 1));
            }
        }
        //author:唐务强
        //按钮为等号时
        if (e.getSource().equals(buttonEqual)) {
            String expression = inputText.getText();
            //如果输入框不为0且不为空的时候
            if (!expression.equals("0") && !expression.equals("")) {
                outputText.setText(outputText.getText() + expression);

            }
            //当等号没有出现时才能输入等号
            if (equalBook == 0) {
                //补全右括号
                for (int i = 0; i < LeftNum - RightNum; i++) {
                    outputText.setText(outputText.getText() + ')');
                }
                String s1=inputText.getText();
                String s2=outputText.getText();
               // System.out.println(s1);
                //System.out.println(s2);
                String str = new Calculator(s2).Calculated(); //得到表达式之后在Calculator中的Calculated中开始进行计算
                if (!str.equals("Error!")) //返回的不是错误信息
                {
                   // System.out.println(s2);
                    //System.out.println(str);
                    inputText.setText("");
                    outputText.setText(s2+"="+str);
                    equalBook=1;
                }
                else {
                    s2 += "=";
                    inputText.setText("");
                    outputText.setText(s2);
                    equalBook=1;
                }
            }
        }
    }
}
package Calcultor;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Stack;

public class Calculator {
    private String expression; //存储表达式
    private Map<String, Integer> priority = new HashMap<>();

    /**
     * @param expression
     * @构造方法
     */
    public Calculator(String expression) {
        init();
        this.expression = expression;
    }

    /**
     * @初始化
     */
    public void init() {
        priority.put("/", 1);
        priority.put("*", 1);
        priority.put("-", 0);
        priority.put("+", 0);
        priority.put("(", -1);
        priority.put(")", -1);
        priority.put("#", -2);
    }

    /**
     * @return boolean
     * @表达式的合法性检测
     */
    public boolean Check() {
        int backets = 0;
        //从左向右扫描
        for (int i = 0; i < expression.length(); i++) {
            switch (expression.charAt(i)) {
                case '(':
                    ++backets;
                    break; //'('加1
                case ')':
                    --backets; //')'减1
                    if (backets < 0) //中间出现'('少于')'的情况
                        return false;
                    break;
                case '/':
                case '*':
                case '+':
                    if (i == 0) return false; // '/'、'*'、'+'不能出现首位
                    if (i > 0 && (expression.charAt(i - 1) == '/' || expression.charAt(i - 1) == '*' || expression.charAt(i - 1) == '+' || expression.charAt(i - 1) == '-' || expression.charAt(i - 1) == '('))
                        return false; //运算符不能连续出现且前面不能为'('
                case '-':
                    if (i == expression.length() - 1) return false; //运算符不能出现在尾部
                    if (expression.charAt(i + 1) == '/' || expression.charAt(i + 1) == '*' || expression.charAt(i + 1) == '+' || expression.charAt(i + 1) == '-' || expression.charAt(i + 1) == ')')
                        return false; //运算符不能连续出现且后面不能为')'
            }
        }
        if (backets != 0) //如果括号不匹配
            return false;
        return true;
    }

    /**
     * @return Stack
     * @中缀表达式转换为后缀表达式
     */
    public Stack<String> Conversion() {
        Stack<String> s1 = new Stack<>();
        Stack<String> s2 = new Stack<>();
        s1.push("#"); //将最低优先级的#符号放入S1栈,为了方便统一后续操作
        for (int i = 0; i < expression.length(); i++) { //循环遍历表达式
            switch (expression.charAt(i)) {
                case '(':
                    s1.push("(");
                    break; //读取到左括号,直接压入S1栈
                case ')': //若取出的字符是")",则将距离S1栈栈顶最近的"("之间的运算符,逐个出栈,依次送入S2栈,此时抛弃"("。
                    while (!s1.peek().equals("(")) {
                        s2.push(s1.pop());
                    }
                    s1.pop();
                    break;
                case '/':
                case '*':
                case '-':
                case '+':
                    /*
                     * 若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,
                     * 如果该运算符优先级(不包括括号运算符)大于S1栈栈顶运算符优先级,则将该运算符进S1栈,
                     * 否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,
                     * 最后将该运算符送入S1栈。
                     * */
                    if (priority.get(expression.charAt(i) + "") > priority.get(s1.peek())) {
                        s1.push(expression.charAt(i) + "");
                    } else {
                        while (!(priority.get(expression.charAt(i) + "") > priority.get(s1.peek()))) {
                            s2.push(s1.pop());
                        }
                        s1.push(expression.charAt(i) + "");
                    }
                    break;
                default:
                    //若取出的字符是操作数,则分析出完整的运算数
                    StringBuilder num = new StringBuilder();
                    while (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.') {
                        num.append(expression.charAt(i));
                        if (i + 1 < expression.length() && (Character.isDigit(expression.charAt(i + 1)) || expression.charAt(i + 1) == '.'))
                            ++i;
                        else break;
                    }
                    //该操作数直接送入S2栈
                    s2.push(num.toString());
                    break;
            }
        }
        //将S1栈内所有运算符(不包括"#"),逐个出栈,依次送入S2栈。
        while (!s1.peek().equals("#"))
            s2.push(s1.pop());
        //由于栈的特性,S2应做一下逆序处理
        Stack<String> stack = new Stack<>();
        while (!s2.empty()) {
            stack.push(s2.pop());
        }
        return stack; //返回S2的逆序栈
    }

    /**
     * @return String
     * @逆波兰式的求值
     */
    public String Calculated() {
        if (!this.Check()) //合法性检验
            return "Error!"; //不合法返回"Error!"
        Stack<String> stack = Conversion(); //得到逆波兰表达式
        Stack<Double> tmp = new Stack<>(); //声明一个栈
        while (!stack.empty()) {
            String s = stack.pop(); //取出逆波兰中的值
            if (Character.isDigit(s.charAt(0))) //如果是操作数
                tmp.push(Double.parseDouble(s)); //直接进入tmp栈
            else {//如果是运算符,取出两个数进行计算
                double b = tmp.pop();
                double a = tmp.pop();
                switch (s) {
                    case "/":
                        if (b == 0.0) //如果除数为0,报错
                            return "Error!";
                        tmp.push(Div(a, b));
                        break;
                    case "*":
                        tmp.push(Mul(a, b));
                        break;
                    case "-":
                        tmp.push(Sub(a, b));
                        break;
                    case "+":
                        tmp.push(Add(a, b));
                        break;
                }
            }
        }
        return tmp.pop().toString();
    }

    public double Div(double a, double b) {
        BigDecimal a1 = new BigDecimal(a);
        BigDecimal b1 = new BigDecimal(b);
        return a1.divide(b1, 5, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    public double Mul(double a, double b) {
        return a * b;
    }

    public double Sub(double a, double b) {
        return a - b;
    }

    public double Add(double a, double b) {
        return a + b;
    }
}

本文地址:https://blog.csdn.net/weixin_44313771/article/details/110188755

《Java之混合计算器的实现.doc》

下载本文的Word格式文档,以方便收藏与打印。