首页 > 编程语言 >用Java实现计算器软件设计

用Java实现计算器软件设计

时间:2023-10-12 23:44:55浏览次数:42  
标签:Java String 软件设计 计算器 添加 操作符 按钮 new 表达式

Java编写个人计算器软件

一、所需要实现的功能

1.该计算器需要实现加、减、乘、除、开平方功能。

2.需要有一个运行的UI界面,可以和电脑自带的计算器相比较。

该界面要有一个文本输入框,用来显示输入的表达式;

若干个按钮,用来用来显示数字以及操作符;

当点击按钮时,按钮上面对应的文本要显示在文本输入框中,并完成计算。

二、项目思想

1.通过Java Swing包和Java awt包完成计算器的基本运算和UI界面的设计,达到美观以及方便运用。

2.通过将日常熟悉的中缀表达式转换成符合计算机运算规则的后缀表达式,这里会涉及到栈、数组和集合的数据结构与算法。

三、字符串的拆分

  因为表达式的输入是以字符串的形式输入进去的,即一整个表达式是一个字符串,在将中缀表达式转换为后缀表达式时,需要将长字符串拆分成短字符串,也就是说一个数字是一个字符串,一个操作符也是一个字符串。当有小数输入时要特别注意,要判断最后有没有溢出。

四、中缀表达式转换为后缀表达式步骤

  1.先创建一个字符栈,用于保存操作符;在创建一个数组,用于保存后缀表达式。

  2.按照从左至右的顺序遍历表达式,

    (1)如果遇到的字符为操作数,则直接进入数组;

    (2)如果遇到的是操作符,则进行以下判断:

      如果栈为空:操作符就直接入栈;

      如果栈不为空:那就判断遇到的字符和栈顶元素的优先级,

           如果遇到的操作符优先级高于栈顶元素优先级,遇到的操作符便入栈;

           否则(遇到的操作符优先级小于等于栈顶元素),栈顶元素出栈,并追加到后缀表达式中,直到栈顶元素优先级小于遇到的操作符优先级,或者栈为空时停止出栈,最后将遇到的操作符入栈。

    (3)如果遇到左括号“( ”,则直接入栈。

    (4)如果遇到右括号“ )”,则栈中元素依次出栈,并追加到后缀表达式,直到左括号出栈为止(左括号不追加到后缀表达式)。

    (5)当表达式扫描完后,检查一遍栈是否为空,若不为空,则将栈中元素依次出栈,并追加到后缀表达式中。

五、UI界面设计

  涉及到界面设计时,Java有一个专门的UI设计工具类JFarme,在这个包下面我们可以进行UI界面的设计,比如窗口的创建与设置、控制面板的创建与设置,按钮的创建与设置,文本框的创建与设置,还有为按钮添加事件,来指定该按钮的作用。

六、详细代码

1.先写一个工具类calculate,用来存放计算器实现的功能

1.1 将数学表达式拆分

	private static List<String> split(String num) {// 返回值为数组list
		List<String> list = new ArrayList<>();//List是一个集合
		int len = num.length();

		int start = 0;
		int end = 0;

		for (int i = 0; i < len; i++) {// i表示当前索引,指向一个个的字符
			char tmp = num.charAt(i);// 获取当前字符
			if (isOperator(tmp)) {// 如果tmp是运算符,就入栈
				list.add(tmp + "");
				continue;
			}
			// 如果是数字或者小数点
			start = i;// start表示指向一个小数的开始,例:2.3的2
//				if(i+1<len) {//判断是否还有下一个字符
//					char next=num.charAt(i+1);//获取当前字符;
//					//最后i+1可能会出现越界行为,
//					//此时在外面再加一个判断语句,当i+1<len即不越界时
//					//才判断next指向的是不是运算符
//					while(i<len && !isOperator(next)) {
//						i++;
//						if(i+1>=len) break;//如果越界则退出循环,所有字符也都遍历结束
//						next=num.charAt(i+1);
//					}
//				}

			// 对上面部分做出优化
			while (i + 1 < len && !isOperator(num.charAt(i + 1))) {
				i++;
			}

			String str = num.substring(start, i + 1);// 字符串截取,得到小数5.2
			list.add(str);// 把获得的小数添加到栈

		}
		return list;
	}
	

1.2 将拆分后的表达式转换为后缀表达式

这里我们就会需要到前面所说的后缀转化的方法,其中会涉及到栈、数组、队列的相关知识,忘了的小伙伴就要翻翻之前的数据结构了呦!

	private static List<String> toPostfix(String num){
		List<String> list=split(num);//获取表达式的各个元素
		
		List<String> exp=new ArrayList<>(list.size()); //用于保存后缀表达式
		
		//运算符暂存在栈中,数值保存在数组中
		Stack<String> optStack=new Stack<>();//暂存运算符
		
		//遍历集合中分割后的表达式(操作符或运算符)
		for(String e:list ) {
			//一、如果是操作数
			if(!isOperator(e)){
				exp.add(e);//添加
				continue;
			}
			//二、如果是操作符
			//1.如果栈为空,操作符入栈
			if(optStack.isEmpty()) {
				optStack.push(e);
				continue;
			}
			//2.如果栈不为空,查看栈顶元素
			String top=optStack.peek();	//查看栈顶元素		
			//2.1如果遇到的操作符元素的优先级高于栈顶元素,待入栈操作符入栈
			if(judgePriority(e,top)) {//遇到的>栈顶,true
				optStack.push(e);//入栈
				continue;
			}
			//2.2否则(遇到的操作符优先级<=栈顶操作符优先级),栈顶元素出栈,
			//	直到栈顶元素优先级小于遇到的操作符,或者栈为空时停止出栈
			while(!optStack.isEmpty() && !judgePriority(e,top)) {
				exp.add(top);//操作符入数组,跟在操作数后面
				optStack.pop();//栈顶出栈
				if(optStack.size()>0) {
					top=optStack.peek();
				}
				
			}
			
			//将当前操作符入栈
			optStack.push(e);
			
		}

		//栈不为空,剩余操作符全部出栈,追加到后面
		while(!optStack.isEmpty()) {
			exp.add(optStack.pop());
		}
		
		return exp;
	}

1.3 通过后缀表达式得到结果

	private static String getResultByPostFix(List<String> exp) {
		//遍历集合中的元素
		for(int i=0;i<exp.size();i++) {
			String val=exp.get(i);//获取当前的元素
			if(!isOperator(val)) {//如果当前元素是操作数,则继续遍历
				continue;
			}
			//如果是运算符,则把该操作符前两位数进行计算
			double result=0;
			double prevOne=Double.parseDouble(exp.get(i-1));//获取操作符前一个数
			double prevTwo=Double.parseDouble(exp.get(i-2));//前二的数
			//判断运算符类型
			switch(val) {
			case "+":
				result=prevOne+prevTwo;
				break;
			case "-":
				result=prevOne-prevTwo;
				break;
			case "*":
				result=prevOne*prevTwo;
				break;	
			case "/":
				result=prevOne/prevTwo;
				break;	
			}
			
			/* 计算完后,这三个字符串就要退出,不再参与
			 * 原来的操作符位置i被新的结果result替换,+""是因为都是字符串
			 * 原来的操作数退出
			 * 下标i变为i-2;
			 */
			exp.set(i, result+"");//替换
			exp.remove(i-1);//移除
			exp.remove(i-2);//移除
			i=i-2;
			
		}
		return exp.get(0);
	}

1.4 操作符优先级的判断

	/* 判断运算符优先级
	 * opt1优先级>opt2,则为true
	 * opt1优先级<=opt2,则为false
	 */
	private static boolean judgePriority(String opt1,String opt2) {
		if( eq(opt1,"+","-")) {
			return false;//opt1"+或-" <= opt2"*或/"
			
		}
		
		if(eq(opt2,"+","-")) {
			return true;//opt1"*或/" > opt2"+或-"
		}
		
		return false;//opt1"*或/" = opt2"*或/"
		
		
		
	}

这里我写了一个eq方法,用来判断是否有两个元素相等,就可以简化上面if语句的判断条件,不然就会写一大串,看起来比较麻烦。

	//public用于判断strs是否存在一个元素和src相等,只要存在一个相等则返回true
	public static boolean eq(String src,String...strs) {//strs是一个数组
		for(String str:strs) {
			if(src.equals(strs)) {
				return true;
			}
		}
		
		return false;
	}

2.UI界面的实现

完成了前面的计算器的计算原理,难道我们每次都要在运行窗口去计算吗?这也太麻烦了对不对,嗯!是的呢!那么......激动人心到时候来啦!接下来就要设计好看的计圈器界面了。

2.1 窗口的创建

这里我对比了电脑自带的计算器,参考他的布局做了自己的计算器界面。第一张图片是电脑自带的计算器,第二张是自己做的计算器界面,由于功能比较少,所以大家不要嫌弃哈!

		//设置窗口名字
		this.setTitle("我的个人计算器");
		//设置窗口大小
		this.setSize(400, 500);
		
		//设置窗口不可改变大小
		this.setResizable(false);
		
		//设置窗口可视化
		this.setVisible(true);
		//设置窗口关闭
		this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		//DISPOSE_ON_CLOSE:点击右上角的“X”只关闭当前窗口,
		//EXIT_ON_CLOSE:结束窗口所在的应用程序。在窗口被关闭的时候会退出JVM,软件所有窗口都会关闭

2.2 添加文本框

		//创建输入框
		display=new JTextField();
		//设置输入框宽高
		display.setPreferredSize(new Dimension(400,50));
		//设置输入框字体类型,样式,大小
		display.setFont(new Font("Arail",Font.PLAIN,20));
		//设置文本对齐方式,右对齐
		display.setHorizontalAlignment(SwingConstants.RIGHT);
		//设置边距
		display.setMargin(new Insets(10,10,10,10));
		//将输入框添加到窗口
		this.add(display,BorderLayout.NORTH);

2.3 添加按钮

因为添加的按钮比较多,且按钮的功能不同,0~9这十个数字以及加减乘除、小数点这些只需要点击时输入文本就行,不需要实质的运算,当然这里的实质运算是在calcuater工具类完成的,因此只需要把它输进去就行,可以批量添加事件;而“清除”“删除”“等于”这些就需要在点击后立即做出反应,所以是要单独添加事件的。

	//创建按钮,添加事件
	private JButton creatButton(String text) {
		return creatButton(text,true);
	}
	
	//该方法用于,创建按钮
	//flag=true添加事件,否则不添加
	private JButton creatButton(String text,boolean flag) {
		JButton btn=new JButton(text);//创建按钮,并指定文本内容
		btn.setFont(new Font("Arail",Font.PLAIN,20));
		
		//增加一个事件,让文本显示在输入框(所以输入框的定义也要放在之前)
		if(flag) {
			btn.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent e) {
					// TODO Auto-generated method stub
					String msg=display.getText();//获取文本
					display.setText(msg+text);//拼接,点一个数字输入一个数字
					
				}
				
			});
		}
		
		return btn;
	}
	//该方法用于,批量把按钮添加到面板,把js添加到com中
	private void addToComponent(JComponent com,JComponent...js) {
		for(JComponent j:js) {
			com.add(j);
		}
	}

按钮要在控制面板上才会起作用,所以还要创建面板,一定要把按钮添加到面板中,不然它是不会显示出来的!

		//创建控制面板
		JPanel panel=new JPanel();
		//分割区域
		panel.setLayout(new GridLayout(5,4));
		//添加按钮
		for(int i=0;i<10;i++) {
			JButton btn=creatButton(i+"");//添加数字按钮
			btn.setFont(new Font("Arail",Font.PLAIN,20));//设置字体,样式,大小
			panel.add(btn);//把按钮添加到面板中
			
		}
		JButton add=creatButton("+");
		JButton substract=creatButton("-");
		JButton multiply=creatButton("*");
		JButton divide=creatButton("/");
		JButton point=creatButton(".",true);//小数点
		JButton eq=creatButton("=",false);
		JButton clear=creatButton("c",false);//清除,整体删除
		JButton del=creatButton("x",false);//删除,一个字符一个字符删
		//批量添加按钮到面板
		addToComponent(panel,add,substract,multiply,divide,point,eq,clear,del);

		//把面板添加到窗口中
		this.add(panel, BorderLayout.CENTER);

2.4 给按钮添加事件

给按钮添加事件的意思就是,点击这个按钮之后会有什么样的反应,对于特别的按钮就需要一个个的添加了。
给”清除”添加事件

		clear.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				display.setText("");
				
			}
			
		});

给“删除”添加事件

		del.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				String msg=display.getText();//获取文本
				if(msg.length()>0) {//有输入时才删除
					display.setText(msg.substring(0,msg.length()-1));	
				
				}
				
			}
			
		});

给“等于”添加事件

		eq.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				if(display.getText().length()>0) {
					String result=calculatorUtils.start(display.getText());
					display.setText(result);
				}
				}
				
			
		});

那么经过上面的一系列操作,我们的计算器软件大概就做好了,如果想让我们的计算器更加美观,那么就需要多学习学习UI界面设计的一些知识了,不过设计一个基本的样式这些就大概足够了。

七、总结与心得

在做这个软件之前,可以说是从来没有完完整整的做出一个软件,之前的课程虽然学了很多,这些内容也是学过的,或者多多少少了解过一点边缘化对象,但是自己没有把知识体系建立起来,感觉像是一段一段的记忆在自己脑子里乱窜,没有秩序的胡乱用,给我一种学了很多但又不知道学了什么的错觉。通过这个小软件的设计与开发我感觉自己收获良多!

标签:Java,String,软件设计,计算器,添加,操作符,按钮,new,表达式
From: https://www.cnblogs.com/momo-swj/p/17754368.html

相关文章

  • 汇编实战!手把手教你从“计算器”入门汇编语言
    基于汇编语言的简单整数计算器设计与实现 (此代码仅供学习使用,请勿用作其他用途)摘要本论文介绍了一款使用汇编语言编写的简单整数计算器程序,该程序支持基本的四则运算操作,并能处理包含括号的数学表达式。本文通过分析程序的代码结构,宏定义、数据段、子程序以及关键功能的实......
  • 2023-10-12 java学习笔记
    1.安装java环境,点击链接前往下载......
  • java的卸载和安装
    java的卸载删除安装目录删除JAVA_HOME删除path下关于java的目录检测是否删除:java-versionJava的安装百度搜索JDK8,找到下载地址同意协议下载电脑安装版本双击安装记住安装的路径配置环境变量我的电脑——>右击——>属性——>高级系统设置环境变量......
  • Java动手动脑
    继承条件下的构造方法调用输出结果为 首先构造基类。通过super调用基类构造方法,必须是子类构造方法中的第一个语句。为什么子类的构造方法在运行之前,必须调用父类的构造方法?能不能反过来?为什么不能反过来?答:子类的构造方法在运行之前必须调用父类的构造方法,是因为子类继承......
  • day01-java数组
    数组概述数组的定义数组时相同类型的数据的有序集合数组描述的时相同类型的若干个数据,按照一定的先后次序排列组合而成。数组的声明和创建首先必须声明数组变量,才能在程序中使用数组。dateType[]arrayRefVar;或者dataTypearrayRefVar[];//效果相同,但不是所选方法java......
  • JavaScript的工作原理:引擎、运行时和调用堆栈
    概述几乎每个人都已经听说过V8引擎这个概念,大多数人都知道JavaScript是单线程的,或者它使用的是回调队列。在本文中,我们将详细介绍这些概念,并解释JavaScript实际运行的方式。通过了解这些详细信息,你将能够正确地利用其所提供的API编写更好的、非阻塞的应用,这些应用正确地利用了......
  • day01-Java方法
    方法java方法是语句的集合,它们在一起执行一个功能--相当于c中的函数方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子......
  • java的字符串模板
    java的字符串模板介绍java如何解决字符串占位符的问题JEP430字符串在java中是如何构造的在编程中,字符串是无处不在的。在编码过程中,要不断的构造字符串直接使用连字符+对于很短的字符连接是很方便的,但对于多个+操作,就十分麻烦了并且很难读StringBufferStringBuilder可......
  • Java Stream 优化java代码
    使用strteam就是为了代码更加简洁,同时功能又不会收到影响,废话不多说使用原始流使用int、long和double等基本类型时,请使用IntStream、LongStream和DoubleStream等基本流,而不是Integer、Long和Double等装箱类型流。原始流可以通过避免装箱和拆箱的成本来提供更好的性......
  • java数据库与JDBC
    java数据库与JDBCjava与MYSQL1.下载驱动https://dev.mysql.com/downloads/connector/j/https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-j-8.1.0.zip2.导入mysql-connector-j.*.jar包3.然后在src目录下新建一个java类4.写入数据库连接测试代码import......