当前位置:   article > 正文

Java实现计算器

java实现计算器
这个作业属于哪个课程软件工程
这个作业要求在哪里作业要求
这个作业的目标完成一个简易计算器


0.界面展示

在这里插入图片描述

1.项目地址

Gitee
Github

2.PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划2015
• Estimate• 估计这个任务需要多少时间2015
Development开发600840
• Analysis• 需求分析 (包括学习新技术)120150
• Design Spec• 生成设计文档3020
• Design Review• 设计复审1010
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)2020
• Design• 具体设计3060
• Coding• 具体编码300480
• Code Review• 代码复审3050
• Test• 测试(自我测试,修改代码,提交修改)6050
Reporting报告10075
• Test Repor• 测试报告3030
• Size Measurement• 计算工作量2015
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划5030
合计720930

3.解题思路

首先设计计算器的基本界面,通过两个StringBuilder类s1、s2来作为数字的载体,字符op作为操作符
通过按钮的监听事件输入数字以及运算符
在对字符串处理后形成的数字通过读取的操作符进行计算

4.实现过程

①使用JFrame创建出计算器初始界面,并设置大小等参数

	//设置界面的宽高
	this.setSize(500, 600);
	//设置界面的标题
    this.setTitle("计算器");
	//设置界面置顶
	this.setAlwaysOnTop(true);
	//设置界面居中
	this.setLocationRelativeTo(null);
	//固定界面大小
	this.setResizable(false);
	//设置关闭模式
	this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	//取消默认放置模式
	this.setLayout(null);
	//给整个界面添加键盘监听事件
	this.addKeyListener(this);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

②使用JMenuBar为计算器添加菜单,并设置大小等参数

    //创建整个菜单对象
    JMenuBar jMenuBar = new JMenuBar();
    //创建选项下的条目对象
	JMenuItem closeItem = new JMenuItem("关闭计算器");
	JMenuItem accountItem = new JMenuItem("说明");
    //创建菜单上两个选项的对象
    JMenu functionJMenu = new JMenu("功能");
    JMenu helpJMenu = new JMenu("帮助");
    //将每一个选项下的条目添加到选项中
    functionJMenu.add(closeItem);
    helpJMenu.add(accountItem);
    //给条目绑定事件
    closeItem.addActionListener(this);
    accountItem.addActionListener(this);
    //将菜单的两个选项添加到菜单中
    jMenuBar.add(functionJMenu);
    jMenuBar.add(helpJMenu);
    //给整个界面设置菜单
    this.setJMenuBar(jMenuBar);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

③JTextArea创建显示屏,JButton作为计算器的按钮,创建一个字符串数组与其绑定,并通过addActionListener()绑定事件

	private String[] buttons = {
            "AC", "删除", "%", "/",
            "7", "8", "9", "*",
            "4", "5", "6", "-",
            "1", "2", "3", "+",
            "00", "0", ".", "="
    };
    private JButton[] button = new JButton[buttons.length];
	JTextArea display = new JTextArea();
	//计算器屏幕大小
	display.setPreferredSize(new Dimension(450, 200));
    //屏幕字体
    display.setWrapStyleWord(true
    display.setRows(2);
    display.setFont(new Font("Times New Roman", Font.PLAIN, 50));
    display.setEditable(false);
    for (int i = 0; i < button.length; i++) {
        button[i] = new JButton(" " + buttons[i] + " ");
        button[i].setPreferredSize(new Dimension(50, 60));
        button[i].addActionListener(this);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

④通过JPanel创建面板,将按钮和显示屏添加入面板,再将面板添加至主界面

	JPanel p1 = new JPanel();
	JPanel p2 = new JPanel();
	//放在中心位置
	this.add(p1, BorderLayout.CENTER)
	//放在下面
	this.add(p2, BorderLayout.SOUTH);
	p1.setSize(400, 100);
	p1.add(display);
	//设置按键的布局
	p2.setLayout(new GridLayout(5, 4, 5, 5));
	for (int i = 0; i < button.length; i++) {
        p2.add(button[i]);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

⑤使用StringBuilder作为数据的载体,通过append()方法存储读取的字符,使用一个默认值为‘$’字符作为操作符,当读取到运算符号时将其覆盖,运算结束时再置为默认值

	//定义
	StringBuilder s1 = new StringBuilder();
	StringBuilder s2 = new StringBuilder();
	char op = '$';
  • 1
  • 2
  • 3
  • 4

⑥处理各个按钮绑定的事件,包括通过按钮读取数据以及菜单

@Override
public void actionPerformed(ActionEvent e) {
    Object obj = e.getSource();
    if (obj == closeItem) {
        //直接关闭虚拟机
        System.exit(0);
    } else if (obj == accountItem) {
        //创建一个弹窗对象
        JDialog jDialog = new JDialog();
        //创建一个管理图片的容器对象
        JLabel jLabel = new JLabel(new ImageIcon("img\\help.jpg"));
        jLabel.setBounds(0, 0, 400, 400);
        jDialog.getContentPane().add(jLabel);
        jDialog.setSize(781, 780);
        jDialog.setAlwaysOnTop(true);
        //弹框居中
        jDialog.setLocationRelativeTo(null);
        //弹框不关闭无法操作下面的界面
        jDialog.setModal(true);
        //让弹框显示出来
        jDialog.setVisible(true);
    } else {
        if (obj == button[0]) {
            // AC
            display.setText("");
            s1 = new StringBuilder();
            s2 = new StringBuilder();
            op = '$';
        } else if (obj == button[button.length - 1]) {
            // =
            CalAndShow();
        } else if (obj == button[1]) {
            // 删除
            if (s1.length() == 0) {
                //创建一个弹窗对象
                JDialog jDialog = new JDialog();
                //创建一个容器对象
                JLabel jLabel = new JLabel("没有可删除的数字!");
                jDialog.getContentPane().add(jLabel);
                jDialog.setSize(150, 150);
                jDialog.setAlwaysOnTop(true);
                //弹框居中
                jDialog.setLocationRelativeTo(null);
                //弹框不关闭无法操作下面的界面
                jDialog.setModal(true);
                //让弹框显示出来
                jDialog.setVisible(true);
            } else if (op == '$') {
                //删除整个三角函数符号
                if (s1.charAt(s1.length() - 1) == 's' || s1.charAt(s1.length() - 1) == 'n') {
                    s1.deleteCharAt(s1.length() - 1);
                    s1.deleteCharAt(s1.length() - 1);
                }
                s1.deleteCharAt(s1.length() - 1);
                display.setText(s1.toString());
            } else if (s2.length() == 0) {
                op = '$';
                display.setText(s1.toString());
            } else {
                if (s2.charAt(s2.length() - 1) == 's' || s2.charAt(s2.length() - 1) == 'n') {
                    s2.deleteCharAt(s2.length() - 1);
                    s2.deleteCharAt(s2.length() - 1);
                }
                s2.deleteCharAt(s2.length() - 1);
                display.setText(s1.toString() + op + s2);
            }
        } else {
            for (int i = 2; i < button.length - 1; i++) {
                if (obj == button[i]) {
                    display.append(buttons[i]);
                    if ((buttons[i].charAt(0) >= '0') && (buttons[i].charAt(0) <= '9')
                            || buttons[i].charAt(0) == '.' || buttons[i].charAt(0) == '√' || buttons[i].charAt(0) == 'Π'
                            || buttons[i].charAt(0) == 's' || buttons[i].charAt(0) == 'c' || buttons[i].charAt(0) == 't'
                            || buttons[i].charAt(0) == '-' && display.getText().endsWith("n" + buttons[i])
                            || buttons[i].charAt(0) == '-' && display.getText().endsWith("s" + buttons[i])) {
                        if (op == '$') {
                            s1.append(buttons[i]);
                        } else {
                            s2.append(buttons[i]);
                        }
                    } else {
                        if (op != '$') {
                            if (s2.length() == 0) {
                                display.setText(s1.toString() + buttons[i]);
                            } else {
                                String temp = String.valueOf(op);
                                CalAndShow();
                                display.append(temp);
                            }
                        }
                        op = buttons[i].charAt(0);
                    }
                    break;
                }
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

⑦读取数字完成进行计算时,先对StringBuilder进行处理,返回double类型的数据,若数据异常返回Double.MAX_VALUE;
(单次运算中sin、cos、tan、根号同时出现其二或一种出现多次都视为数据输入异常)

//处理数据
private double dealNum(String s) {
    if (countTimes(s, ".") > 1) {
        return Double.MAX_VALUE;
    }
    //每次运算不允许多个Π的输入
    if (countTimes(s, "Π") > 1) {
        return Double.MAX_VALUE;
    }
    double sign = s.contains("Π") ? Math.PI : 1;
    int flag = 0;
    String[] opp = {"√", "sin", "cos", "tan"};
    for (String value : opp) {
        if (s.contains(value)) {
            flag += countTimes(s, value);
        }
    }
    if (flag == 0) {
        if (sign == 1) {
            return Double.parseDouble(s);
        } else {
            String temp1 = s.substring(0, s.length() - 1);
            if (temp1.equals("-")) {
                return -Math.PI;
            } else if (temp1.length() == 0) {
                return Math.PI;
            } else {
                return Double.parseDouble(temp1) * sign;
            }
        }
    } else if (flag == 1) {
        String temp = s.substring(s.charAt(0) == '√' ? 1 : 3);
        if (sign == Math.PI) {
            temp = temp.substring(0, temp.length() - 1);
        }
        if (temp.equals("-")) {
            temp = "-1";
        } else if (temp.length() == 0 && sign != 1) {
            temp = "-1";
        }
        if (temp.length() == 0) {
            return Double.MAX_VALUE;
        }
        if (s.charAt(0) == '√') {
            return Math.sqrt(Double.parseDouble(temp) * sign);
        } else if (s.charAt(0) == 's') {
            return Math.sin(Double.parseDouble(temp) * sign);
        } else if (s.charAt(0) == 'c') {
            return Math.cos(Double.parseDouble(temp) * sign);
        } else if (s.charAt(0) == 't') {
            return Math.tan(Double.parseDouble(temp) * sign);
        }
    }
    return Double.MAX_VALUE;
}
//子字符串出现次数
public static int countTimes(String s, String s1) {
    int old = s.length();
    String ss = s.replace(s1, "");
    return (old - ss.length()) / s1.length();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

⑧根据操作符op以及返回的数进行计算与显示结果,每次计算后都将结果存入s1,将s2清空

public void CalAndShow() {
    double num1 = dealNum(s1.toString());
    double num2 = 0;
    if (num1 == Double.MAX_VALUE) {
        showDataErr();
    }
    if (s2.length() != 0) {
        num2 = dealNum(s2.toString());
        if (num2 == Double.MAX_VALUE) {
            showDataErr();
        }
        if (op == '+') {
            num1 += num2;
        } else if (op == '-') {
            num1 -= num2;
        } else if (op == '×') {
            num1 *= num2;
        } else if (op == '%') {
            num1 %= num2;
        } else if (op == '^') {
            num1 = Math.pow(num1, num2);
        } else if (op == '÷') {
            if (num2 == 0) {
                showNumErr();
                num2 = Double.MAX_VALUE;
            } else {
                num1 /= num2;
            }
        }
        s2 = new StringBuilder();
        op = '$';
    }
    if (num1 % 1 == 0) {
        s1 = new StringBuilder(String.valueOf((int) num1));
    } else {
        s1 = new StringBuilder(String.valueOf(num1));
    }
    if (num1 == Double.MAX_VALUE || num2 == Double.MAX_VALUE) {
        s1 = new StringBuilder();
    }
    display.setText(s1.toString());
}

//数据输入错误
private void showDataErr() {
    //创建一个弹窗对象
    JDialog jDialog = new JDialog();
    //创建一个容器对象
    JLabel jLabel = new JLabel("      数据输入错误!!!");
    jDialog.getContentPane().add(jLabel);
    jDialog.setSize(150, 150);
    jDialog.setAlwaysOnTop(true);
    //弹框居中
    jDialog.setLocationRelativeTo(null);
    //弹框不关闭无法操作下面的界面
    jDialog.setModal(true);
    //让弹框显示出来
    jDialog.setVisible(true);
}

//除数为零报错
private void showNumErr() {
    //创建一个弹窗对象
    JDialog jDialog = new JDialog();
    //创建一个容器对象
    JLabel jLabel = new JLabel("      除数不能为零!!!");
    jDialog.getContentPane().add(jLabel);
    jDialog.setSize(150, 150);
    jDialog.setAlwaysOnTop(true);
    //弹框居中
    jDialog.setLocationRelativeTo(null);
    //弹框不关闭无法操作下面的界面
    jDialog.setModal(true);
    //让弹框显示出来
    jDialog.setVisible(true);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

5.性能改进

①在进行删除操作时,只能删除单个字符,需要点击三次删除键才能删除三角函数的符号
改进方法:通过读取屏幕上的内容,若为三角函数符号,则连续删除2个字符串再进行正常的删除操作

    //删除整个三角函数符号
    if (s1.charAt(s1.length() - 1) == 's' || s1.charAt(s1.length() - 1) == 'n') {
        s1.deleteCharAt(s1.length() - 1);
        s1.deleteCharAt(s1.length() - 1);
    }
  • 1
  • 2
  • 3
  • 4
  • 5

②在处理数据过程中,若遇到Π,定义一个标识sign,默认值为1,若字符串中出现Π,设sign为Π,只需最后返回的数字都 * sign进而减少代码长度

	double sign = s.contains("Π") ? Math.PI : 1;
	......
	return Double.parseDouble(temp1) * sign;
  • 1
  • 2
  • 3

6.单元测试

利用Junit框架进行单元测试

通过随机数得到两个数据,对各种运算进行100次测试
如下的加法测试与sin函数测试

// 加法测试
@Test
public void AddTest() {
    Random r = new Random();
    double[] ans = new double[100];
    double[] res = new double[100];
    for (int i = 0; i < 100; i++) {
        double x = r.nextDouble();
        double y = r.nextDouble();
        ans[i] = x + y;
        cul.s1 = new StringBuilder(String.valueOf(x));
        cul.s2 = new StringBuilder(String.valueOf(y));
        cul.op = '+';
        cul.CalAndShow();
        res[i] = Double.parseDouble(cul.display.getText());
    }
    Assert.assertArrayEquals("Error", ans, res, 0.01);
}
//sin函数
@Test
public void sinTest() {
    Random r = new Random();
	double[] ans = new double[100];
	double[] res = new double[100];
	for (int i = 0; i < 100; i++) {
		double x = r.nextDouble();
		ans[i] = Math.sin(x);
		cul.s1 = new StringBuilder("sin" + x);
		cul.CalAndShow();
		res[i] = Double.parseDouble(cul.display.getText());
	}
	Assert.assertArrayEquals("Error", ans, res, 0.01);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

测试结果如下:
在这里插入图片描述

7.异常处理

输入异常数据或除数为零时

通过弹窗进行报错

Alt

Alt

8.心得体会

心路历程:从一开始设计了只有加减乘除取余操作的简易计算器(带后缀_Pre的文件),后来根据作业要求在原来计算器的基础上一步步添加了科学计算(次方、三角函数等)

学习收获:通过本次作业,我学会了如何使用Java创建具有可视化界面以及软件单元测试,提高了Java的编程能力,在编码过程中的一次次调试也增强了发现与解决问题的能力

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/275777
推荐阅读
相关标签
  

闽ICP备14008679号