实验一简易计算器

实验一 计算器的程序制作
一.项目概述
1.项目目标和主要内容
用Java.swing来实现一个简单计算器,计算器界面的实现和核心算法的编写。
2.要实现的功能
(1基本的加,减,乘,除,四则运算
(2平方运算
(3开方运算
(4求余运算
(5)可显示输入运算及输出结果
二.项目设计
1.编写过成
(1)构建计算器框架。
(2)插入计算器按钮数字及符号采用同大小80*40并注册监听器。
(3)编写中缀表达式转换为后缀表达式,计算开放,平方等运算。
2.关键算法分析
在这里插入图片描述

从左向右依次读取算术表达式的元素X,分以下情况进行不同的处理:
(1)如果X是操作数,直接入队
(2)如果X是运算符,再分以下情况:
a)如果栈为空,直接入栈。
b)如果X==”(“,直接入栈。
c)如果X==”)“,则将栈里的元素逐个出栈,并入队到后缀表达式队列中,直到第一 个配对的"("出栈。 (注:“”和“)”都不入队)
d)如果是其他操作符(±*1) ,则和栈顶元素进行比较优先级。如果栈顶元素的优先级大于等于X,则出栈并把栈中弹出的元素入队,直到栈顶元素的优先级小于X或者栈为空。弹出完这些元素后,才将遇到的操作符压入到栈中。
(3)最后将栈中剩余的操作符全部入队。
在这里插入图片描述
首先准备-一个栈Res_ Stack.
1、从左开始向右遍历后缀表达式的元素。
2、如果取到的元素是操作数,直接入栈Res
_Stack, 如果是运算符,从栈中弹出2个数进行运算,然后把运算结果入栈
3、当遍历完后缀表达式时,计算结果就保存在栈里了。
三.程序运行结果
在这里插入图片描述
在这里插入图片描述

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Objects;

import javax.swing.*;
class Calculator extends JFrame implements ActionListener {
    private final String[] KEYS = { "7", "8", "9", "AC", "e", "pi", "6", "5", "4", "+", "-", "sqrt", "1", "2", "3", "*", "/",
            "%", "0", ".", "(", ")", "=", "x^x" };
    private JButton keys[] = new JButton[KEYS.length];
    private JTextArea resultText = new JTextArea("0.0");
    private JTextArea History = new JTextArea();
    private JPanel jp2=new JPanel();
    private JScrollPane gdt1=new JScrollPane(resultText);
    private JScrollPane gdt2=new JScrollPane(History);//新建一个垂直滚动滑条
    private String b = "";
    int flash=0;
    int flash2=0;
    int flash3=0;

    public Calculator() {
        super("hu的计算器");

        JPanel jp1 = new JPanel();
        jp1.setBounds(20,18,255,215);//计算过程面板窗口位置及大小
        jp1.setLayout(new GridLayout());
        jp2.setBounds(290,18,250,215);//历史记录面板窗口位置及大小
        jp2.setLayout(new GridLayout());

        resultText.setLineWrap(true);
        resultText.setWrapStyleWord(true);
        History.setLineWrap(true);
        History.setWrapStyleWord(true);//两个窗口激活自动换行

        History.setEditable(false);// 文本框不允许修改结果
        resultText.setEditable(false);
        gdt1.setViewportView(resultText);//使滚动条显示出来
        gdt2.setViewportView(History);
        gdt1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        gdt2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//设置让垂直滚动条一直显示
        jp1.add(gdt1);//将滚动条添加入面板窗口中
        jp2.add(gdt2);
        this.add(jp1);
        this.add(jp2);//将面板添加到总窗体中
        this.setLayout(null);
        // 放置按钮
        int x = 10, y = 250;
        for (int i = 0; i < KEYS.length; i++)
        {
            keys[i] = new JButton();
            keys[i].setText(KEYS[i]);
            keys[i].setBounds(x, y, 80, 40);
            if (x < 385) {
                x += 90;
            } else {
                x = 10;
                y += 45;
            }
            this.add(keys[i]);
        }
        for (int i = 0; i < KEYS.length; i++)// 每个按钮都注册事件监听器
        {
            keys[i].addActionListener(this);
        }
        this.setResizable(false);
        this.setBounds(500, 200, 567, 480);
        this.setVisible(true);
    }

    // 事件处理
    public void actionPerformed(ActionEvent e)
    {
        //History.setText(b);//使输入的表达式显示在历史记录文本框中
        String label=e.getActionCommand();//获得事件源的标签
        if(Objects.equals(label, "="))//
        {
            resultText.setText(this.b);
            History.setText(History.getText()+resultText.getText());
            if(label.equals("="))//调用计算方法,得出最终结果
            {
                String[] s =houzhui(this.b);
                String result=Result(s);
                this.b=result+"";
                //更新文本框,当前结果在字符串b中,并未删除,下一次输入接着此结果以实现连续运算
                resultText.setText(this.b);
                History.setText(History.getText()+"="+resultText.getText()+"\n");
            }
        }
        else if(Objects.equals(label, "AC"))//清空按钮,消除显示屏文本框前面所有的输入和结果
        {
            this.b="";
            resultText.setText("0");//更新文本域的显示,显示初始值;
            flash=0;
        }
        else if(Objects.equals(label, "sqrt"))
        {
            String n=kfys(this.b);
            resultText.setText("sqrt"+"("+this.b+")"+"="+n);//使运算表达式显示在输入界面
            History.setText(History.getText()+"sqrt"+"("+this.b+")"+"=");//获取输入界面的运算表达式并使其显示在历史记录文本框
            this.b=n;
        }
        else if(Objects.equals(label, "x*x"))
        {
            String m=pfys(this.b);
            resultText.setText(this.b+"^2"+"="+m);//使运算表达式显示在输入界面
            History.setText(History.getText()+this.b+"^2"+"=");//获取输入界面的运算表达式并使其显示在历史记录文本框
            this.b=m;
        }
        else if(Objects.equals(label, "e") || Objects.equals(label, "pi"))
        {
            if(label.equals("e"))
            {
                String m=String.valueOf(2.71828);//将e的值以字符串的形式传给m
                this.b=this.b+m;//保留显示m之前输入的运算符或数字字符继续下一步运算
                resultText.setText(this.b);
                // History.setText(History.getText()+this.b);
            }
            if(label.equals("pi"))
            {
                String m=String.valueOf(3.14159265);
                this.b=this.b+m;
                resultText.setText(this.b);
                // History.setText(History.getText()+this.b);
            }
        }
        else if(label.equals(".")){

            if(flash==0){
                this.b=this.b+label;
                resultText.setText(this.b);
                flash=1;
            }
        }
        else if(label.equals("(")) {
            flash2++;
            if ((b.charAt(b.length()-1)!=')')&&(b.charAt(b.length()-1)!='0') &&(b.charAt(b.length()-1)!='1') &&(b.charAt(b.length()-1)!='2')&&(b.charAt(b.length()-1)!='3') &&(b.charAt(b.length()-1)!='4') &&(b.charAt(b.length()-1)!='5')&&(b.charAt(b.length()-1)!='6') &&(b.charAt(b.length()-1)!='7') &&(b.charAt(b.length()-1)!='8')&&(b.charAt(b.length()-1)!='9') )  {
                this.b = this.b + label;
                resultText.setText(this.b);
            }
        }
        else if(label.equals(")")) {
             flash3++;
            if ((b.charAt(b.length()-1)!='/') &&(b.charAt(b.length()-1)!='*') &&(b.charAt(b.length()-1)!='+')&&(b.charAt(b.length()-1)!='-')&&(b.charAt(b.length()-1)!='%'&&(b.charAt(b.length()-1)!='(') &&flash2>=flash3)) {
                this.b = this.b + label;
                resultText.setText(this.b);
            }
        }

        else if(label.equals("+")) {
            if ((b.charAt(b.length()-1)!='/') &&(b.charAt(b.length()-1)!='*') &&(b.charAt(b.length()-1)!='+')&&(b.charAt(b.length()-1)!='-')&&(b.charAt(b.length()-1)!='%')&&(b.charAt(b.length()-1)!='(')&&(b.charAt(b.length()-1)!='(') ) {
                this.b = this.b + label;
                resultText.setText(this.b);
            }
        }
        else if(label.equals("-")) {
            if ((b.charAt(b.length()-1)!='/') &&(b.charAt(b.length()-1)!='*')&&(b.charAt(b.length()-1)!='+')&&(b.charAt(b.length()-1)!='-')&&(b.charAt(b.length()-1)!='%')&&(b.charAt(b.length()-1)!='(')&&(b.charAt(b.length()-1)!='(') ) {
                this.b = this.b + label;
                resultText.setText(this.b);
            }
        }
        else if(label.equals("*")) {
            if ((b.charAt(b.length()-1)!='/') &&(b.charAt(b.length()-1)!='*') &&(b.charAt(b.length()-1)!='+')&&(b.charAt(b.length()-1)!='-')&&(b.charAt(b.length()-1)!='%')&&(b.charAt(b.length()-1)!='(')&&(b.charAt(b.length()-1)!='(') ) {
                this.b = this.b + label;
                resultText.setText(this.b);
            }
        }
        else if(label.equals("/")) {
            if ((b.charAt(b.length()-1)!='/') &&(b.charAt(b.length()-1)!='*') &&(b.charAt(b.length()-1)!='+')&&(b.charAt(b.length()-1)!='-')&&(b.charAt(b.length()-1)!='%')&&(b.charAt(b.length()-1)!='(')&&(b.charAt(b.length()-1)!='(') ) {
                this.b = this.b + label;
                resultText.setText(this.b);
            }
        }
        else if(label.equals("%")) {
            if ((b.charAt(b.length()-1)!='/') &&(b.charAt(b.length()-1)!='*') &&(b.charAt(b.length()-1)!='+')&&(b.charAt(b.length()-1)!='-')&&(b.charAt(b.length()-1)!='%')&&(b.charAt(b.length()-1)!='(')&&(b.charAt(b.length()-1)!='(') ) {
                this.b = this.b + label;
                resultText.setText(this.b);
            }
        }
        else
        {
            if(label.equals("+")||label.equals("-")||label.equals("*")||label.equals("/")||label.equals("%"))flash=0;
            this.b=this.b+label;
            resultText.setText(this.b);
            // History.setText(History.getText()+this.b);

        }
        //History.setText(History.getText()+this.b);//使输入的表达式显示在历史记录文本框中

    }
    //将中缀表达式转换为后缀表达式
    private String[] houzhui(String str) {
        String s = "";// 用于承接多位数的字符串
        char[] opStack = new char[100];// 静态栈,对用户输入的操作符进行处理,用于存储运算符
        String[] postQueue = new String[100];// 后缀表达式字符串数组,为了将多位数存储为独立的字符串
        int top = -1, j = 0;// 静态指针top,控制变量j
        for(int i=0;i<str.length();i++){
            if(str.charAt(i)=='('&&str.charAt(i+1)=='-'){//将"(-"变为”(0-“
                str=str.substring(0,i+1)+"0"+str.substring(i+1);
            }
        }
        for (int i = 0; i < str.length(); i++)// 遍历中缀表达式
        // indexof函数,返回字串首次出现的位置;charAt函数返回index位置处的字符;
        {
            if ("0123456789.".indexOf(str.charAt(i)) >= 0) // 遇到数字字符的情况直接入队
            {
                s = "";// 作为承接字符,每次开始时都要清空
                for (; i < str.length() && "0123456789.".indexOf(str.charAt(i)) >= 0; i++) {
                    s = s + str.charAt(i);
                    //比如,中缀表达式:234+4*2,我们扫描这个字符串的时候,s的作用相当于用来存储长度为3个字符的操作数:234
                }
                i--;
                postQueue[j] = s;// 数字字符直接加入后缀表达式
                j++;
            }
            else if ("(".indexOf(str.charAt(i)) >= 0) {// 遇到左括号
                top++;
                opStack[top] = str.charAt(i);// 左括号入栈
            }
            else if (")".indexOf(str.charAt(i)) >= 0) {// 遇到右括号
                for (;;)// 栈顶元素循环出栈,直到遇到左括号为止
                {
                    if (opStack[top] != '(') {// 栈顶元素不是左括号
                        postQueue[j] = opStack[top] + "";// 栈顶元素出栈
                        j++;
                        top--;
                    } else { // 找到栈顶元素是左括号
                        top--;// 删除栈顶左括号
                        break;// 循环结束
                    }
                }
            }
            else if ("*%/+-".indexOf(str.charAt(i)) >= 0)// 遇到运算符
            {
                if (top == -1)
                {// 若栈为空则直接入栈
                    top++;
                    opStack[top] = str.charAt(i);
                }
                else if ("*%/".indexOf(opStack[top]) >= 0)
                {// 当栈顶元素为高优先级运算符时,让栈顶元素出栈进入后缀表达式后,当前运算符再入栈
                    postQueue[j] = opStack[top] + "";
                    j++;
                    opStack[top] = str.charAt(i);
                }
                else
                {
                    top++;
                    opStack[top] = str.charAt(i);// 当前元素入栈
                }
            }
        }
        while (top != -1) {// 遍历结束后将栈中剩余元素依次出栈进入后缀表达式
            postQueue[j] = opStack[top] + "";
            j++;
            top--;
        }
        return postQueue;
    }

    //开方运算方法
    public String kfys(String str) {
        String result = "";
        double a = Double.parseDouble(str), b = 0;
        b = Math.sqrt(a);
        result = String.valueOf(b);//将运算结果转换为string类型并赋给string类型的变量result
        return result;
    }

    //平方运算方法
    public String pfys(String str) {
        String result = "";
        double a = Double.parseDouble(str), b = 0;
        b = Math.pow(a, 2);
        result = String.valueOf(b);
        return result;
    }

    // 计算后缀表达式,并返回最终结果
    public String Result(String[] str) {
        String[] Result = new String[100];// 顺序存储的栈,数据类型为字符串
        int Top = -1;// 静态指针Top
        for (int i = 0; str[i] != null; i++) {
            if ("+-*%/".indexOf(str[i]) < 0) {  //遇到数字,直接入栈
                Top++;
                Result[Top] = str[i];
            }
            if ("+-*%/".indexOf(str[i]) >= 0)// 遇到运算符字符,将栈顶两个元素出栈计算并将结果返回栈顶
            {
                double x, y, n;
                x = Double.parseDouble(Result[Top]);// 顺序出栈两个数字字符串,并转换为double类型
                Top--;
                y = Double.parseDouble(Result[Top]);
                Top--;
                if ("*".indexOf(str[i]) >= 0) {
                    n = y * x;
                    Top++;
                    Result[Top] = String.valueOf(n);// 将运算结果重新入栈

                }
                if ("/".indexOf(str[i]) >= 0)
                {
                    if (x == 0)// 被除数不允许为0
                    {
                        String s = "error!";
                        return s;
                    } else {
                        n = y / x;
                        Top++;
                        Result[Top] = String.valueOf(n);// 将运算结果重新入栈
                    }
                }
                if ("%".indexOf(str[i]) >= 0)
                {
                    if (x == 0)// 被除数不允许为0
                    {
                        String s = "error!";
                        return s;
                    } else {
                        n = y % x;
                        Top++;
                        Result[Top] = String.valueOf(n);// 将运算结果重新入栈
                    }
                }
                if ("-".indexOf(str[i]) >= 0) {
                    n = y - x;
                    Top++;
                    Result[Top] = String.valueOf(n);// 将运算结果重新入栈
                }
                if ("+".indexOf(str[i]) >= 0) {
                    n = y + x;
                    Top++;
                    Result[Top] = String.valueOf(n);// 将运算结果重新入栈
                }
            }
        }
        return Result[Top];// 返回最终结果
    }

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

参考文献
Java编写简单计算器–实现篇@阿雪狼
JAVA制作简易计算器@自娱自乐选手
java简单计算器的制作@星辰-大海
Java实现常规计算器(网格布局)@样young
java中indexof()的几种用法@wust-lh
等等

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值