使用idea手搓java计算器

工具准备:IDEA(开发工具)、exe4j(打包工具)

效果截图

软件下载体验

下载链接:百度网盘 请输入提取码

提取码:root

源码 

//Calculator类中的代码

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.util.*;
import java.util.List;

public class Calculator implements ActionListener {
    private final JFrame f;
    private final JPanel mp;
    //定义两个文本框用来显示算式和结果
    private final JTextField show, showed;
    //定义数字、控制、运算符号按钮
    private final Map<String, JButton> b = new HashMap<>();//buttons
    //定义算式的字符串表示
    private String exp, outcome;
    private final Color fontColor = Color.BLACK;
    private final Font theDefaultFont = new Font(Font.SERIF, Font.BOLD, 25);

    public static void main(String[] args) {
        Calculator c = new Calculator();
        c.display();
    }

    //在构造函数中初始化控件和变量
    private Calculator() {
        f = new JFrame("计算器");
        mp = new JPanel();
        show = new JTextField("0");//创建单行文本控件
        showed = new JTextField();
        String[] keys = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "CE", "C", "DEL", "+", "-", "*", "/", "+/-", ".", "="};
        for (String key : keys) {
            b.put(key, new JButton(key));
        }
        exp = outcome = "";//初始设置存储算式和结果的字符串为空串
    }

    public void display() {
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭就退出程序
        //设置显示结果的单行文本框相关属性
        show.setFont(new Font(Font.SERIF, Font.BOLD, 40));//设置字体样式
        show.setBorder(BorderFactory.createEmptyBorder());//设置单行文本控件无边框
        show.setHorizontalAlignment(SwingConstants.RIGHT);//设置文本靠右显示
        show.setEnabled(false);//设置单行文本框不能点击
        showed.setFont(theDefaultFont);
        showed.setBorder(BorderFactory.createEmptyBorder());
        showed.setHorizontalAlignment(SwingConstants.RIGHT);
        showed.setEnabled(false);
        //设置按钮为透明
        Calculator calculator = this;
        b.forEach((k, v) -> {
            v.setFont(theDefaultFont);
            v.setForeground(fontColor);
            if ("=".equals(k)) {
                b.get("=").setBackground(Color.CYAN);
                v.setContentAreaFilled(true);
            } else {
                v.setContentAreaFilled(false);
            }
            v.addActionListener(calculator);
        });
        GridBagLayout layout = new GridBagLayout();
        mp.setLayout(layout);
        GridBagConstraints g = new GridBagConstraints();
        g.fill = GridBagConstraints.BOTH;//设置当某个单元格未填满时填满整个空间
        g.weightx = 1.0;//设置窗口变大时缩放比例
        g.weighty = 1.0;
        g.gridx = 0;//定位在第一行第一列
        g.gridy = 0;
        g.gridwidth = GridBagConstraints.REMAINDER;//填满整行
        g.gridheight = 1;//占一行网格
        g.insets = new Insets(5, 5, 0, 5);//设置该组件与其它组件的距离
        layout.setConstraints(showed, g);//将上述
        g.gridx = 0;
        g.gridy = 1;
        g.gridheight = 2;
        g.insets = new Insets(0, 5, 5, 5);
        layout.setConstraints(show, g);
        g.insets = new Insets(5, 5, 5, 5);
        g.gridwidth = 1;
        g.gridheight = 1;
        //按钮大概位置
        setButtonPosition(layout, 3, g, b.get("CE"), b.get("C"), b.get("DEL"), b.get("/"));
        setButtonPosition(layout, 4, g, b.get("7"), b.get("8"), b.get("9"), b.get("*"));
        setButtonPosition(layout, 5, g, b.get("4"), b.get("5"), b.get("6"), b.get("-"));
        setButtonPosition(layout, 6, g, b.get("1"), b.get("2"), b.get("3"), b.get("+"));
        setButtonPosition(layout, 7, g, b.get("+/-"), b.get("0"), b.get("."), b.get("="));
        b.forEach((k, v) -> mp.add(v));
        mp.add(showed);
        mp.add(show);
        f.setContentPane(mp);
        f.setSize(440, 500);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private void setButtonPosition(GridBagLayout layout, int grIdy, GridBagConstraints constraint, JButton but0, JButton but1, JButton but2, JButton but3) {
        constraint.gridy = grIdy;
        constraint.gridx = 0;
        layout.setConstraints(but0, constraint);
        constraint.gridx = 1;
        layout.setConstraints(but1, constraint);
        constraint.gridx = 2;
        layout.setConstraints(but2, constraint);
        constraint.gridx = 3;
        layout.setConstraints(but3, constraint);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        outcome = "";
        if ((e.getSource()) == b.get("CE")) {//清除最后一个输入的操作数
            int pos = posOfLastOperator(exp);//获取最后一个运算符的位置
            if (pos >= 0)
                exp = exp.substring(0, pos + 1);
            else//只有一个操作数直接清空
                exp = "0";
            show.setText(exp);
        } else if ((e.getSource()) == b.get("C")) {//清空算式
            exp = "0";
            show.setText(exp);
        } else if ((e.getSource()) == b.get("del")) {
            //提取字符串开始到倒数第二个字符
            exp = exp.substring(0, exp.length() - 1);
            if (exp.length() == 0)//删除全部的输入后设置显示0
                exp = "0";
            show.setText(exp);
        } else if ((e.getSource()) == b.get("+") || (e.getSource()) == b.get("minus") || (e.getSource()) == b.get("mul") || (e.getSource()) == b.get("div")) {
            if (exp.length() != 0 && (!isOperator(exp.charAt(exp.length() - 1))))//确认必须有数字才能输入运算符
                exp += e.getActionCommand();
            show.setText(exp);
        } else if ((e.getSource()) == b.get("neg")) {
            int pos = posOfLastOperator(exp);
            if (pos >= 0) {//算符中存在多个操作数
                if (isDigit(exp.charAt(exp.length() - 1)))//只有有数字才能置为负数
                    exp = exp.substring(0, pos + 1) + "(-" + exp.substring(pos + 1) + ")";//设置为负数时加上括号以区分与减号
            } else {//只有一个操作数
                if (!Objects.equals(exp, "") && isDigit(exp.charAt(exp.length() - 1)))
                    exp = "-" + exp;
            }
            if (exp.equals(""))//设置当算式为空时显示0
                exp = "0";
            show.setText(exp);
        } else if ((e.getSource()) == b.get("=")) {
            exp += '#';//算式末尾添加’#’
            //从算式中拆分出数字
            String[] nums = exp.split("[^.0-9]");
            List<Double> numLst = new ArrayList<>();
            for (String num : nums) {//将每个数字串转化为Double类型
                if (!"".equals(num))
                    numLst.add(Double.parseDouble(num));
            }
            double out = getValueOfMid(exp, numLst);//利用中缀式求值
            outcome = "" + out;//将求得的结果转为字符串
            exp = exp.substring(0, exp.length() - 1);//去除算式后的’#’
            showed.setText(exp);//第一个单行文本框展示算式
            show.setText(new BigDecimal(outcome).stripTrailingZeros().toPlainString());//第二个单行文本框显示结果
            exp = "";//存储算式的字符串清空
        } else if ((e.getSource()) == b.get("point")) {
            int pos = exp.lastIndexOf('.');//找到最后一个小数点的位置
            if (pos >= 0) {//前后两个小数点间不能都是数字,即不能2.33时又添加一个小数点变为2.33.
                if (isDigit(exp.charAt(exp.length() - 1)) && !isDigitString(exp.substring(pos + 1)))
                    exp += e.getActionCommand();
            } else {//小数点前一个必须是数字
                if (isDigit(exp.charAt(exp.length() - 1)))
                    exp += e.getActionCommand();
            }
            show.setText(exp);
        } else {
            if (Objects.equals(exp, "0"))
                exp = "";
            exp += e.getActionCommand();
            show.setText(exp);
        }
    }

    public static boolean isDigit(char ch) {//判断一个字符是否为数字
        return (ch >= '0' && ch <= '9');
    }

    public boolean isDigitString(String s) {//判断一个字符是否都为数字
        for (int i = 0; i < s.length(); i++) {
            if (!isDigit(s.charAt(i)))
                return false;
        }
        return true;
    }

    public boolean isOperator(char c) {//判断一个字符是否为运算符或’.’
        return (c == '+') || (c == '-') || (c == '*') || (c == '/') || (c == '.');
    }

    public int posOfLastOperator(String s) {//寻找字符串中最后一个运算符(+,-,*,/)的位置
        for (int i = s.length() - 1; i >= 0; i--) {
            if (s.charAt(i) != '.' && isOperator(s.charAt(i)))
                return i;
        }
        return -1;//找不到返回-1
    }

    public static int isp(char ch) {//定义栈中运算符优先级,并将相应算符的优先级返回
        switch (ch) {
            case ')':
                return 4;
            case '*':
            case '/':
                return 3;
            case '+':
            case '-':
                return 2;
            case '(':
                return 1;
            case '#':
                return 0;
        }
        return -1;
    }

    public static int icp(char ch) {//定义栈外运算符优先级,并将相应算符的优先级返回
        switch (ch) {
            case ')':
                return 1;
            case '*':
            case '/':
                return 3;
            case '+':
            case '-':
                return 2;
            case '(':
                return 4;
            case '#':
                return 0;
        }
        return 0;
    }

    public static double compute(double a, char ch, double b) {//将取出的两个操作数与对应的算符进行计算并返回计算结果
        switch (ch) {
            case '+':
                return a + b;
            case '-':
                return a - b;
            case '*':
                return a * b;
            case '/':
                return a / b;
            default:
                break;
        }
        return 0;
    }

    //对输入的算式(中缀式)进行求值
    public static double getValueOfMid(String exp, List<Double> numLst) {
        Stack<Character> OPTR = new Stack<>();//定义算符栈
        Stack<Double> OPND = new Stack<>();//定义操作数栈
        double outcome;//最终结果
        double a, b;//定义两个操作数
        char sym;//定义运算符
        OPTR.push('#');
        int i = 0, j = 0;
        while (exp.charAt(i) != '#' || OPTR.peek() != '#') {
            if (isDigit(exp.charAt(i))) {//遍历到数字时则跳过数字字符串,并将之前划分的double类型数据代替压栈
                while (isDigit(exp.charAt(i)) || exp.charAt(i) == '.') {
                    i++;
                    if (i == exp.length())
                        break;
                }
                i--;
                OPND.push(numLst.get(j));
                j++;
            } else {
                sym = OPTR.peek();
                int m = isp(sym);
                int n = icp(exp.charAt(i));
                if (m < n)//比较栈内和栈外运算符的优先级
                    OPTR.push(exp.charAt(i));//栈内算符优先级小于栈外,则栈外运算符压栈
                else {//栈内运算符优先级大于栈外运算符优先级
                    sym = OPTR.peek();
                    OPTR.pop();//取出栈内的运算符
                    if (sym != '(' && m == n || m > n) {
                        b = OPND.peek();//从操作数栈取出一个操作数
                        OPND.pop();
                        if (!OPND.empty() && OPTR.peek() != '(') {//当操作数栈不为空且不为’(’时继续取出栈中的数进行运算
                            a = OPND.peek();
                            OPND.pop();
                            OPND.push(compute(a, sym, b));
                        } else {//处理负数
                            switch (sym) {//实现一元运算符的运算
                                case '+':
                                    OPND.push(b);
                                    break;
                                case '-':
                                    OPND.push(-b);
                                    break;
                            }
                        }
                        continue;
                    }
                }
            }
            i++;
        }
        outcome = OPND.peek();
        return outcome;
    }
}

exe4j打包流程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值