Java语言编写计算器

本文讲述Java图形用户界面的编写,重点讲述一个简单计算器的实现。

文中程序的运行环境为Windows10 ,编译环境为MyEclipse 8.5。

一个简单的计算器主要实现一下功能和要求:

一:输入,输出

     ①输入:允许输入带有括号的完整计算式(例 6*(3+5)-5÷2)

     ②输出:输出Double类型的结果

二:功能

     ①:基本的加,减,乘,除,四则运算

     ②:平方运算

     ③:开方运算

最终界面如下图:


除了常规的数字按钮和运算符,还有两个常数e,π

主要思想:

一:输入,以及运算的实现

     要实现完整计算式的输入并运算,就得用到计算后缀表达式的算法,和将中缀表达式转换为后缀表达式的算法(这里不再赘述中缀表达式和后缀表达式,以及之后有关栈的知识也不再多说,有兴趣可以阅读数据结构中关于栈的相关章节),这里重点讲解以上两个算法。

     算法1(中缀表达式转后缀表达式):

     因为计算式要在计算器的文本编辑框中显示,所以计算式用字符串记录(定义为字符串)

     规则:从左向右遍历中缀表达式

               ①:遇到数字字符,直接加入后缀表达式

               ②:遇到高优先级运算符,若栈为空直接入栈,若栈不为空,则将当前运算符与栈顶元素比较

                      比较1(栈顶元素也为高优先级运算符):栈顶元素出栈加入后缀表达式,当前运算符入栈。这样的操作使得栈                                                                                     中不会出现连续的高优先级运算符

                      比较2(栈顶元素为'('左括号):将当前元素入栈

                      比较3(栈顶元素为低优先级运算符):将当前元素入栈

               ③:遇到'('左括号,将左括号入栈

               ④:遇到')'右括号,将栈顶元素顺序出栈,直到栈顶元素为左括号,此时删去栈顶的左括号

               ⑤:遇到低优先级运算符,若栈为空直接入栈,若栈不为空,则将当前运算符与栈顶元素比较

                      比较1(栈顶元素也为低优先级运算符):栈顶元素出栈加入后缀表达式,当前运算符入栈。这样的操作使得栈中                                                                                   不会出现连续的低优先级运算符

                      比较2(栈顶元素为'('左括号):将当前运算符入栈

                      比较③(栈顶元素为高优先级运算符):栈顶元素出栈加入后缀表达式,当前运算符入栈

程序段如下(代码段中的注释根据上述讲解过程书写,可以根据步骤阅读)

代码段中用到的某些函数注释:

                 indexof():String.indexof()方法搜索在该字符串上是否出现了作为参数传递的字符串,若找到字符串,则返回字符                                     串首字母的位置(0代表第一个位置),在下面的代码段中,为了判断字符类型用到了该方法。

                 String.valueof():将double类型的浮点数转换为字符串

                 Double.parseDouble():将字符串转化为double类型的浮点数

private String[] yunsuan(String str)
	{
		String s="";//用于承接多位数的字符串
		char a[]=new char[100];//静态的栈
		String jieguo[]=new String[100];//后缀表达式字符串数组,为了将多位数存储为独立的字符串
		int top=-1,j=0;//静态指针top,控制变量j
		for (int i=0;i<str.length();i++)//遍历中缀表达式
		{
			if ("0123456789.".indexOf(str.charAt(i))>=0)//indexof函数见上方注释,遇到数字字符的情况
			{
				s="";//作为承接的字符串,每次开始都要清空
                                for (;i<str.length()&&"0123456789.".indexOf(str.charAt(i))>=0;i++)//将多位数存储在一个字符串中
                                {
                                     s=s+str.charAt(i);
                                }
                                i--;
                                jieguo[j]=s;//数字字符直接加入后缀表达式
                                j++;
			}
			else if ("(".indexOf(str.charAt(i))>=0)//遇到左括号
			{
				top++;
				a[top]=str.charAt(i);//左括号入栈
			}
			else if (")".indexOf(str.charAt(i))>=0)//遇到右括号
			{
				for (;;)//栈顶元素循环出栈,直到找到左括号为止
				{
					if (a[top]!='(')//栈顶元素不是左括号
					{
						jieguo[j]=a[top]+"";//栈顶元素出栈
						j++;
						top--;
					}
					else//找到栈顶元素是左括号
					{
						top--;//删除栈顶的左括号
						break;//循环结束
					}
				}
			}
			else if ("*%÷".indexOf(str.charAt(i))>=0)//遇到高优先级运算符
			{
				if (top==-1)//若栈为空直接入栈
				{
					top++;
					a[top]=str.charAt(i);
				}
				else//栈不为空
				{
					if ("*%÷".indexOf(a[top])>=0)//栈顶元素也为高优先级运算符
					{
						jieguo[j]=a[top]+"";//栈顶元素出栈进入后缀表达式
						j++;
						a[top]=str.charAt(i);//当前运算符入栈
					}
					else if ("(".indexOf(a[top])>=0)//栈顶元素为左括号,当前运算符入栈
					{
						top++;
						a[top]=str.charAt(i);
					}
					else if ("+-".indexOf(a[top])>=0)//栈顶元素为低优先级运算符,当前运算符入栈
					{
						top++;
						a[top]=str.charAt(i);
					}
				}
			}
			else if ("+-".indexOf(str.charAt(i))>=0)//遇到低优先级运算符
			{
				if (top==-1)//栈为空直接入栈
				{
					top++;
					a[top]=str.charAt(i);
				}
				else//栈不为空
				{
					if ("%*÷".indexOf(a[top])>=0)//栈顶元素为高优先级运算符
					{
						jieguo[j]=a[top]+"";//栈顶元素出栈加入后缀表达式
						j++;
						a[top]=str.charAt(i);//当前运算符入栈
					}
					else if ("(".indexOf(a[top])>=0)//栈顶元素为左括号
					{
						top++;
						a[top]=str.charAt(i);//当前运算符入栈
					}
					else if ("+-".indexOf(a[top])>=0)//栈顶元素也为低优先级运算符
					{
						jieguo[j]=a[top]+"";//栈顶元素出栈进入后缀表达式
						j++;
						a[top]=str.charAt(i);//当前元素入栈
					}
				}
			}
		}
		for (;top!=-1;)//遍历结束后将栈中剩余元素依次出栈进入后缀表达式
		{
			jieguo[j]=a[top]+"";
			j++;
			top--;
		}
		return jieguo;
	}

     算法2:计算后缀表达式

                 计算后缀表达式依然借助栈来实现

                 运算规则:遍历后缀表达式

                 ①:遇到数字字符,直接入栈

                 ②:遇到运算符,顺序出栈两个元素(数字),进行运算,将运算结果入栈

                 循环以上步骤最终栈中剩下的那个数字就是最终答案

     程序段如下:
 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]);//顺序出栈两个数字字符串,并转换为double类型的数字
                Top--;
                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);
                }
                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);
                    }
                }
            }
        }
        return Result[Top];//返回最终结果
    }
     算法3:开方运算
      程序段如下(调用了Math.sqrt()函数实现)
public String yunsuan2(String str)
    {
        String result="";
        double a=Double.parseDouble(str),b=0;
        b=Math.sqrt(a);
        result=String.valueOf(b);
        return result;
    }
     算法4:平方运算
      程序段如下(调用了Math.pow()函数实现)
public String yunsuan3(String str)
    {
        String result="";
        double a=Double.parseDouble(str),b=0;
        b=Math.pow(a, 2);
        result=String.valueOf(b);
        return result;
    }

界面设计:

一:框架

 本计算器是基于Swing组建的图形用户界面,采用JFrame框架作为主窗口

       

public class Calculator extends JFrame implements ActionListener
类名Calculator(计算器),继承JFrame框架,实现事件监听器接口

二:文本行,按钮

整个计算器界面,可以随意发挥,我编写的界面最终的样子在文章开头有图片

计算器类中,定义的成员有:

    ①private String[] KEYS={"7","8","9","*","4","5","6","-","1","2","3","+","0","e","π","÷","c","%",".","=","(",")","sqr","x*x"};
    ② private JButton keys[]=new JButton[KEYS.length];
    ③private JTextField resultText = new JTextField("0.0");
    ④private String b="";

①:按钮标签字符串

②:定义按钮数组

③:定义文本行

④:用于存放计算式

构造方法代码段如下(计算器的整体界面完成)

public Calculator()
    {
        super("计算器");
        this.setLayout(null);//未采用任何类型的布局,后面的文本框和按钮显示位置都是自己计算好的位置
        resultText.setBounds(20, 5, 255, 40);//设置文本框大小
        resultText.setHorizontalAlignment(JTextField.RIGHT);//文本框内容右对齐
        resultText.setEditable(false);//文本框不允许修改结果
        this.add(resultText);//新建文本框
        int x=20,y=55;
        for (int i=0;i<KEYS.length;i++)//放置按钮
        {
            keys[i] = new JButton();
            keys[i].setText(KEYS[i]);
            keys[i].setBounds(x, y, 60, 40);
        if(x<215)
            {
                x+=65;
            }
        else
            {
                x = 20;
                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, 300, 400);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setVisible(true);
    }

事件处理(以下代码用同一个字符串来记录计算式和结果,保证了计算式可以连续计算)

public void actionPerformed(ActionEvent e)//处理事件
    {
        String label = e.getActionCommand(); //获得事件源的标签
        if (label=="c"||label=="=")//按钮C清空文本框,消除前面所有的输入和结果
        {
            if(label=="=")//按钮=得出最终结果,调用计算方法
            {
                String s[]=yunsuan(this.b);
                String result=Result(s);
                this.b=result+"";
                resultText.setText(this.b);//更新文本框,当前结果在字符串b中,并未删除,下一次输入是接着这个结果的,这样可以实现连续运算
            }
            else
            {
                this.b="";
                resultText.setText("0");//更新文本域的显示,显示初始值
            }
        }
        else if (label=="sqr")//sqr 按钮计算开方
        {
            String n=yunsuan2(this.b);
            resultText.setText(n);
            this.b=n;
        }
        else if(label=="x*x")//x*x按钮实现某个数的平方
        {
            String m=yunsuan3(this.b);
            resultText.setText(m);
            this.b=m;
        }
        else if(label=="e"||label=="π")
        {
            if (label=="e")//常数e
            {
                String m=String.valueOf(2.71828);
                this.b=this.b+m;
                resultText.setText(this.b);
            }
            if (label=="π")//常数π
            {
                String m=String.valueOf(3.14159265);
                this.b=this.b+m;
                resultText.setText(this.b);
            }
        }
        else
        {
            this.b=this.b+label;
            resultText.setText(this.b);
        }
    }

计算器已经完成,完整代码如下:

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Calculator extends JFrame implements ActionListener
{
    private String[] KEYS={"7","8","9","*","4","5","6","-","1","2","3","+","0","e","π","÷","c","%",".","=","(",")","sqr","x*x"};
    private JButton keys[]=new JButton[KEYS.length];
    private JTextField resultText = new JTextField("0.0");
    private String b="";
    public Calculator()
    {
        super("计算器");
        this.setLayout(null);
        resultText.setBounds(20, 5, 255, 40);
        resultText.setHorizontalAlignment(JTextField.RIGHT);
        resultText.setEditable(false);
        this.add(resultText);
        int x=20,y=55;
        for (int i=0;i<KEYS.length;i++)
        {
            keys[i] = new JButton();
            keys[i].setText(KEYS[i]);
            keys[i].setBounds(x, y, 60, 40);
        if(x<215)
            {
                x+=65;
            }
        else
            {
                x = 20;
                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, 300, 400);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    public void actionPerformed(ActionEvent e)
    {
        String label = e.getActionCommand(); 
        if (label=="c"||label=="=")
        {
            if(label=="=")
            {
                String s[]=yunsuan(this.b);
                String result=Result(s);
                this.b=result+"";
                resultText.setText(this.b);
            }
            else
            {
                this.b="";
                resultText.setText("0");
            }
        }
        else if (label=="sqr")
        {
            String n=yunsuan2(this.b);
            resultText.setText(n);
            this.b=n;
        }
        else if(label=="x*x")
        {
            String m=yunsuan3(this.b);
            resultText.setText(m);
            this.b=m;
        }
        else if(label=="e"||label=="π")
        {
            if (label=="e")
            {
                String m=String.valueOf(2.71828);
                this.b=this.b+m;
                resultText.setText(this.b);
            }
            if (label=="π")
            {
                String m=String.valueOf(3.14159265);
                this.b=this.b+m;
                resultText.setText(this.b);
            }
        }
        else
        {
            this.b=this.b+label;
            resultText.setText(this.b);
        }
    }
    private String[] yunsuan(String str)
	{
		String s="";
		char a[]=new char[100];
		String jieguo[]=new String[100];
		int top=-1,j=0;
		for (int i=0;i<str.length();i++)
		{
			if ("0123456789.".indexOf(str.charAt(i))>=0)
			{
				s="";
                for (;i<str.length()&&"0123456789.".indexOf(str.charAt(i))>=0;i++)
                {
                    s=s+str.charAt(i);
                }
                i--;
                jieguo[j]=s;
                j++;
			}
			else if ("(".indexOf(str.charAt(i))>=0)
			{
				top++;
				a[top]=str.charAt(i);
			}
			else if (")".indexOf(str.charAt(i))>=0)
			{
				for (;;)
				{
					if (a[top]!='(')
					{
						jieguo[j]=a[top]+"";
						j++;
						top--;
					}
					else
					{
						top--;
						break;
					}
				}
			}
			else if ("*%÷".indexOf(str.charAt(i))>=0)
			{
				if (top==-1)
				{
					top++;
					a[top]=str.charAt(i);
				}
				else
				{
					if ("*%÷".indexOf(a[top])>=0)
					{
						jieguo[j]=a[top]+"";
						j++;
						a[top]=str.charAt(i);
					}
					else if ("(".indexOf(a[top])>=0)
					{
						top++;
						a[top]=str.charAt(i);
					}
					else if ("+-".indexOf(a[top])>=0)
					{
						top++;
						a[top]=str.charAt(i);
					}
				}
			}
			else if ("+-".indexOf(str.charAt(i))>=0)
			{
				if (top==-1)
				{
					top++;
					a[top]=str.charAt(i);
				}
				else
				{
					if ("%*÷".indexOf(a[top])>=0)
					{
						jieguo[j]=a[top]+"";
						j++;
						a[top]=str.charAt(i);
					}
					else if ("(".indexOf(a[top])>=0)
					{
						top++;
						a[top]=str.charAt(i);
					}
					else if ("+-".indexOf(a[top])>=0)
					{
						jieguo[j]=a[top]+"";
						j++;
						a[top]=str.charAt(i);
					}
				}
			}
		}
		for (;top!=-1;)
		{
			jieguo[j]=a[top]+"";
			j++;
			top--;
		}
		return jieguo;
	}
    public String yunsuan2(String str)
    {
        String result="";
        double a=Double.parseDouble(str),b=0;
        b=Math.sqrt(a);
        result=String.valueOf(b);
        return result;
    }
    public String yunsuan3(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;
        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]);
                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)
                {
                    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)
                {
                    if (x==0)
                    {
                        String s="ERROR";
                        return s;
                    }
                    else
                    {
                        n=y/x;
                        Top++;
                        Result[Top]=String.valueOf(n);
                    }
                }
                if ("%".indexOf(str[i])>=0)
                {
                    if (x==0)
                    {
                        String s="ERROR";
                        return s;
                    }
                    else

                    {
                        n=y%x;
                        Top++;
                        Result[Top]=String.valueOf(n);
                    }
                }
            }
        }
        return Result[Top];
    }
    public static void main(String arg[])
    {
        Calculator a=new Calculator();
    }
}

该计算器功能有限,只限于日常生活的使用,可以改进的方向很多

一:实现带符号数的运算,例如:-6-6

二:实现复数运算

三:实现多次方的运算

四:实现一元一次方程的运算

五:实现一元二次方程的运算

以上改进方向只是一小部分,对于有一些编程基础的人,可以尝试一下,对于大神这就是小儿科了。

欢迎读者评论,共同交流,共同进步。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页