java简单加、减、乘、除、取模、几次(非负数的)方计算器GUI

简单加减乘除计算器的思路:
1、准备工作:
①定义一个类,继承于JFrame这个类,并且实现ActionListener这个接口
②同时定义一个容器,用来存放按钮。
③定义一个字符串数组及按钮数组,两者的长度是相同的,这样就可以通过遍历这个字符串数组新建按钮
④定义一个文本框,每一次点击按钮,文本框上出现相应的数字

2、设置窗口的主要参数,比如大小是多少等。
3、遍历字符串数组,从而将每一个按钮上有相应的数字,并且可以设置按钮的大小及按钮中的数字字体、大小。同时将按钮设置好之后,每一个按钮都要添加监听控件
4、将按钮添加到容器中
5、遍历结束之后,就将这个容器添加到窗口中

点击按钮之后,处理过程的具体思路是:如果当前按钮对应的字符串是=号,那么就可以开始计算结果了,通过将文本框上的字符串转换成后缀表达式进行计算,如果不是=号,那么就将按钮对应的字符串添加到文本框中

步骤:

步骤一、判断当前按钮的上对应的字符串是否是等于号,如果不是,那么将会有两种情况:
①如果当前按钮对应的字符串是基本运算符或者数字的话,那么直接将当前的按钮添加到文本框中,通过setText方法,设置文本框的内容,但是如果是直接setText()的话,那么之前文本框的内容就会发生改变,所以应该是先获取当前文本框的内容string,然后将string和当前按钮对应的字符串进行拼接,此时string才是完整的,才可以setText(),里面的参数是string。比如说,当前的文本框的内容是3+5,点击按钮之后,按钮对应的字符串是+号,那么如果直接将setText(当前按钮的字符串),那么最终显示再文本框中的字符串只有+,而没有了3+5。所以应该先调用方法getText()获取当前文本框上的内容,然后进行拼接,得到字符串string = 3+5+,此时再将string作为setText的参数才可以再文本框上显示 3+5+。

②如果cha当前按钮对应的字符串对应的不是基本运算符或者数字,而是“返回”这个字符串,那么就要删除一个字符,那么首先获取当前文本框中的字符串string,并且新建一个字符串str,然后进行遍历拼接,从而可以得到,注意因为“返回”只能清除一个字符,那么并没有完当前文本框的字符串string,只是遍历到string.length()-1,从而实现删除一个字符。

步骤二、如果当前按钮对应的字符串对应的是=号,那么开始计算,具体过程:
获取当前文本框中的内容(是一个中缀表达式)
②将中缀表达式转换成为后缀表达式,具体过程:

  • 从左到右开始遍历中缀表达式,

  • 如果遇到的是数字,那么就考虑是否为多位数字或者小数,如果是,那么就要拼接,拼接完毕之后,将其压入到栈1中

  • 如果遇到的是基本的运算符,那么就要将分几种情况考虑:
    1)如果栈2为空或者栈2的栈顶是左括号或者当前的符号就是左括号,那么直接将其压入栈2
    2)如果遇到的是右括号,那么就通过循环遍历栈2,从栈2中跳出符号,然后将其这些符号压入到栈1中, 直到栈2的栈顶符号为左括号,结束遍历,最后还要将左括号从栈2中跳出,从而消除左括号
    3)如果符号都不符合上面的几种情况,那么还要分几种情况:
    ①如果当前的符号优先级大于栈顶符号的优先级,那么直接入栈,
    ②当前符号的优先级小于或者等于栈顶符号的优先级,那么就从栈2中跳出,并将这个符号压入到栈1,最后才可以将当前符号压入到栈2
    4)压入完毕之后,将栈1中的符号全部压入到栈2,否则如果将栈2中的符号压入到栈1中,得到的是后缀表达式的倒序
    5)定义一个字符串列表,用于存放后缀表达式

步骤三、获得后缀表达式之后,遍历字符串列表,计算运算结果,这一步也需要配合一个栈来实现,如果遇到的是一个数字,那么就将其压入栈中,否则遇到的是基本运算符,那么就从栈中跳出两个数字,注意首先跳出栈的是num1,然后跳出栈的是num2,那么进行减法运算、除法运算必须是num2 - num1,num2 / num1,否则运算结果是不正确的。比如原来的中缀表达式为2+3÷5,那么字符串列表为[2,3,5,÷,+],那么遇到÷号之后,首先跳出栈的数字是num1 = 5,然后num2为3,那么这里运算应该是num2 / num1,同时在计算的时候注意运算规则,比如除数不可以为0等情况。

代码:

/**
 * 制作一个简单计算器GUI
 * 1、定义一个类,从而使得其继承于窗口,并且实现于监听接口
 * 2、对窗口进行设置相应的参数
 * 3、向窗口中添加按钮,从而实现基本的运算
 * 4、向窗口中添加文本框,这样在点击按钮的时候就会出现相应的数字
 * 5、将向按钮中添加监听控件,从而点击按钮的时候,将对应的数字添加到文本框中,通过调用文本框的setText方法即可
 * 6、点击到等号的时候,将文本框中的字符串转换成后缀表达式,进行相应的运算
 */

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;


public class Calculator extends JFrame implements ActionListener {
    public JPanel panel = new JPanel();
    public String[] string = {"(",")","^","%","7","8","9","x","4","5","6","÷","1","2","3","-","0",".","=","+","返回"};
    public JButton[] b = new JButton[string.length];
    public JTextField text = new JTextField();//设置文本框
    public Stack<String> stack1 = new Stack<>();
    public Stack<String> stack2 = new Stack<>();
    public void setframe(){
        Dimension dimension = new Dimension(738,90);//设置文本框的大小
        text.setPreferredSize(dimension);
        panel.add(text,BorderLayout.NORTH);
        for(int i = 0; i<string.length; i++){
            Dimension dimension1 = new Dimension(180,80);
            b[i] = new JButton(string[i]);//初始化按钮
            b[i].setFont(new Font("宋体",Font.BOLD,36));//设置按钮中的字体
            b[i].setPreferredSize(dimension1);//设置按钮的大小
            b[i].addActionListener(this);//将每一个容器都添加监听控件
            panel.add(b[i]);//将按钮添加到容器中
        }
        this.add(panel);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//可以退出
        this.setVisible(true);
        this.setBounds(100,100,800,650);
        this.setTitle("my calculator");

    }
    public static void main(String[] args){
        new Calculator().setframe();
    }
    @Override
    public void actionPerformed(ActionEvent e) {
         if(!e.getActionCommand().equals("=")) {
             //没有等于=号的时候,考虑两种情况,一是当前按钮不是返回键,而是当前按钮是返回键
             if(!e.getActionCommand().equals("返回")) {
                 //如果当前按钮不是返回键,那么就将当前按钮上的字符添加到文本框中
                 text.setText(text.getText() + e.getActionCommand());//获取文本框中的字符
                 text.setFont(new Font("宋体", Font.BOLD, 36));//设置文本框中的字体
             }else{
//清除文本框的最后一个字符,方法一:通过遍历即可,此时不需要考虑文本框是否为空
//                 String str = "";
//                 String str2 = text.getText();
//                 for(int i = 0; i < str2.length() - 1; i++){
//                     str += str2.substring(i,i+1);
//                 }
//                 text.setText(str);
                 String str1 = text.getText();
                 StringBuffer str = new StringBuffer(str1);
                 if(str1.length() != 0) {
                     str.deleteCharAt(str1.length() - 1);
                     String string = str.toString();
                     text.setText(string);
                 }else{
                 //如果文本框的内容为空了,那么就不可以在清除了,此时就将文本框设置成空字符串即可,如果没有这一步的话,在文本框为空的时候,点击返回,就会报错,而方法一就不会
                     text.setText("");
                 }
             }
         }else if(e.getActionCommand().equals("=")){
             //如果是等号,那么就将从文本框中获取字符串,然后进行中缀表达式转换成后缀表达式
             String str = text.getText();//从文本框中获取字符串
             //调用方法,从而将中缀表达式转换成为后缀表达式
             List<String> list = getSufExpression(str);//获得后缀表达式
             //计算后缀表达式的结果
             try{
                 String result = getResult(list);
                 text.setText(result);
             }catch(Exception e1){
                 text.setText(e1.getMessage());
             }
         }

    }

    /**
     * 调用方法,从而获得后缀表达式
     * 思路:
     * 1、定义两个栈,栈1用于储存数字,栈2用于储存基本的运算符
     * 2、从左到右开始遍历字符串,如果遇到的是数字,那么就考虑是否为多位数字或者小数,如果是,那么就要拼接
     * 3、如果遇到的是基本的运算符,那么就要将分几种情况考虑:
     * 1)如果栈2为空或者栈2的栈顶是左括号或者当前的符号就是左括号,那么直接将其压入栈2
     * 2)如果遇到的是右括号,那么就从栈2中跳出符号,然后将其这些符号压入到栈1中,直到遇到的栈顶符号为左括号,最后还要将左括号
     * 从栈2中跳出,从而消除左括号
     * 3)如果符号是基本运算符号,那么还要分几种情况:
     * ①如果当前的符号优先级大于栈顶符号的优先级,那么直接入栈,
     * ②当前符号的优先级小于或者等于栈顶符号的优先级,那么就从栈2中跳出,并将这个符号压入到栈1,最后才可以将当前符号压入到栈2
     * 4、压入完毕之后,将栈1中的符号全部压入到栈2,否则如果将栈2中的符号压入到栈1中,得到的是后缀表达式的倒序
     * 5、定义一个字符串列表,用于存放后缀表达式
     * @param string
     * @return
     */
    public List<String> getSufExpression(String string){
        List<String> list = new ArrayList<String>();
        String keepNum = "";//定义一个空字符串,用于多位数字、小数的拼接
        for(int i = 0; i<string.length(); i++){
            String str = string.substring(i,i+1);
            if(isOper(str)){
                //如果是基本运算符
                if(stack2.empty() || stack2.peek().equals("(") || str.equals("(")){
                    //如果当前符号是左括号或者栈2为空或者栈顶符号是左括号,那么就直接将符号入栈
                    stack2.push(str);
                }else if(str.equals(")")){
                    //如果当前符号是右括号,那么从栈2中不断跳出符号,然后将这些从栈2跳出的符号压入到栈1中,直到栈顶符号位左括号,然后将左括号从栈2中跳出
                    while(!stack2.peek().equals("(")){
                        String item = stack2.pop();
                        stack1.push(item);
                    }
                    stack2.pop();//消除左括号
                }else{
                    //如果都不符合上面的情况,那么就开始比较优先级
                    if(getPriority(str) > getPriority(stack2.peek())){
                        //如果当前符号的优先级大于栈2栈顶符号的优先级,那么就将当前符号直接入栈
                        stack2.push(str);
                    }else{
                        //当前符号的优先级小于或者等于栈顶符号的优先级,那么就从栈顶中跳出符号,并将这个跳出的符号压入到栈1中,然后再将当前符号入栈
                        String item2 = stack2.pop();
                        stack1.push(item2);
                        stack2.push(str);
                    }
                }
            }else{
                //如果当前符号不是基本的运算符,那么就将其压入到栈1,同时还要考虑多位数字、小数的情况
                keepNum += str;
                int j ;
                for(j = i+1; j < string.length(); j++){
                    String item3 = string.substring(j,j+1);
                    if(isOper(item3)){
                        //如果当前符号是基本的运算符,那么就停止数字的拼接
                        break;
                    }
                    keepNum += item3;
                }
                stack1.push(keepNum);
                keepNum = "";//重置keepNum
                i = j - 1;
            }
        }
        //遍历完毕之后,将栈1中的所有符号都压入到栈2中,从而遍历栈2的时候得到的是后缀表达式
        while(!stack1.empty()){
            String item = stack1.pop();
            stack2.push(item);
        }

        //遍历栈2元素,然后将其添加到字符串列表中储存
        while(!stack2.empty()){
            String item = stack2.pop();
            list.add(item);
        }
        return list;//返回字符串列表,从而得到的是后缀表达式
    }

    /**
     * 计算后缀表达式的结果
     * 思路:通过配合栈来使用
     * 1、定义一个栈
     * 2、如果遇到的是数字,那么就将其压入栈中
     * 3、遇到的是基本运算符,那么就从栈中跳出两个数字,并进行相应的运算
     * 4、遍历结束之后,栈中剩余的那个数字就是运算结果
     * @param list  后缀表达式
     * @return
     */
    public String getResult(List<String> list){
       for(int i = 0; i<list.size() ; i++){
           String item = list.get(i);
           if(isOper(item)){
                   //如果当前的符号是基本运算符,那么就从栈中跳出两个数字,然后进行相应的运算
                   double num1 = Double.parseDouble(stack1.pop());
                   double num2 = Double.parseDouble(stack1.pop());//由于栈是先进后出的,那么进行运算的时候,应该是num2 - num1等
                   //进行运算之后,将相应的结果压入栈中
                   switch(item){
                       case "+":
                           stack1.push(String.valueOf(num1 + num2));
                           break;
                       case "-":
                           stack1.push(String.valueOf(num2 - num1));
                           break;
                       case "÷":
                           if(num1 == 0)
                               throw new RuntimeException("错误,除数不可以为0");
                           stack1.push(String.valueOf(num2 / num1));
                           break;
                       case "x":
                           stack1.push(String.valueOf(num2 * num1));
                           break;
                       case "%":
                           if(num1 == 0)
                               throw new RuntimeException("错误,取模时除数不可以为0");
                           stack1.push(String.valueOf(num2 % num1));
                           break;
                       case "^":
                           double value = Math.pow(num2,num1);
                           stack1.push(String.valueOf(value));
                           break;
                       default:
                           break;
                   }
           }else{
               //如果当前符号不是基本运算符,那么就将其压入栈中
               stack1.push(item);
           }
       }
       return stack1.pop();//返回运算结果
    }
    /**
     * 判断是否为基本运算符
     * @param string
     * @return
     */
    public boolean isOper(String string){
        return (string.equals("^")||string.equals("+") ||string.equals("-")||string.equals("x") ||string.equals("÷") ||string.equals("=")||string.equals("(") || string.equals(")") || string.equals("%"));
    }

    /**
     * 比较基本运算符的优先级
     * @param string
     * @return
     */
    public int getPriority(String string){
        if(string.equals("^")){
            return 4;
        }if(string.equals("%")){
            return 3;
        }else if(string.equals("÷") || string.equals("x")){
            return 2;
        }else if(string.equals("+") || string.equals("-")){
            return 1;
        }
        return 0;//都不符合,那么就返回0
    }
}


现在的代码不足之处就是功能有些少,同时还有一种情况是不可以处理的,比如直接输入-10%2,或者-10+2,就是最开始文本框的首个字符是基本运算符得没有办法处理,如果以后想到了,会修改的,请大家见谅。同时如果哪里有不足之处,请大家指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值