用Java制作简单的计算器

这篇具有很好参考价值的文章主要介绍了用Java制作简单的计算器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本篇文章主要是提供思路,当然文章末尾也又提供了源代码。

代码也是写了几天,重要的理解,不是直接复制粘贴就交作业了。

转载请注明出处,尊重作者劳动成果。

目录

界面的设计:

事件的响应:

计算:

详细代码如下:

 总结:


要制作一个简单的计算器,首先就是对于界面的设计,然后就是其功能的实现。

对于事件的实现大概就分下面几个步骤。

  1. 确定事件源和监听源
  2. 实现监听器的接口
  3. 将事件源注册到监听器

然后就一起进入代码的编写吧,我是分成了几个发放来编写功能,最后有最终的代码,可以直接运行,这要注意的是,直接粘贴的话,类名和文件名要一样哦。

界面的设计:

他最上面是要有一个文本框,中间要有很多的按钮,我这里大的框架是采用BorderLayout类布局管理器,其中他的NORTH(容器顶部)是添加了一个FlowLayout类布局管理器,FlowLayout里面是一个文本框,CENTER(容器的中间)是添加了一个GirdLayout类布局管理器,形成网格状的按钮,WEST(容器的左侧),EAST(容器的右侧),SOUTH(容器底部),这些是通过添加一个空白的标签来占位置的,让界面更加好看一点。

	//创建显示器面板,采用默认的流布局
	final JPanel viewPanel =new JPanel();
	//创建显示器
	final JTextField textField=new JTextField();
	//创建按钮面板
	final JPanel buttonPanel=new JPanel();
	//创建网络布局管理器对象
	final GridLayout gridLayout=new GridLayout(0,4);
	//按钮里面的内容
	String [][]names= {
			{"**","ln","lg","clear"},
			{"sin","cos","tan","X"},
			{"PI","//","%","/"},
			{"7","8","9","*"},
			{"4","5","6","-"},
			{"1","2","3","+"},
			{"_/``","0",".","="}};

	//创建按钮对象
	JButton[][] buttons=new JButton[names.length][4];
	//创建左侧的占位标签
	final JLabel leftLabel=new JLabel();
	//创建右侧的占位标签
	final JLabel rightLabel=new JLabel();
	//创建下侧的占位标签
	final JLabel bottomLabel=new JLabel();
//初始化组件
	public void initModule() {
		//初始化显示器相关数据
		textField.setEditable(false);//设置显示器不可编辑
		textField.setHorizontalAlignment(SwingConstants.RIGHT);
		textField.setColumns(35);//调节文本框的宽度
		textField.setPreferredSize(new Dimension(500,40));
	
		//初始化面板按钮
		gridLayout.setVgap(10);//设置组件的水平间距
		gridLayout.setHgap(10);//设置组件的垂直间距
		//初始化按钮对象
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				buttons[row][col]=new JButton(names[row][col]);//创建按钮
			}
		}
		
		//设置左侧标签的宽度
		leftLabel.setPreferredSize(new Dimension(10,0));
		//设置右侧标签的宽度
		rightLabel.setPreferredSize(new Dimension(10,0));
		//设置底部标签的宽度,组件的有高度,可以没宽度,和两边相反
		bottomLabel.setPreferredSize(new Dimension(0,10));
	}
//初始化面板
	public void initPanel() {
		//初始化组件
		initModule();
		
		viewPanel.add(textField);
		viewPanel.setPreferredSize(new Dimension(100,80));
		this.getContentPane().add(viewPanel,BorderLayout.NORTH);
		
		
		buttonPanel.setLayout(gridLayout);//按钮面板采用网络布局
		this.getContentPane().add(buttonPanel,BorderLayout.CENTER);//将按钮面板添加到窗体中间
		//把按钮添加到按钮面板中,虽然可以和初始化按钮写一起,但是便于理解还是把他们分开写了
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				buttonPanel.add(buttons[row][col]);
			}
		}
		this.getContentPane().add(leftLabel,BorderLayout.WEST);
		this.getContentPane().add(rightLabel,BorderLayout.EAST);
		this.getContentPane().add(bottomLabel,BorderLayout.SOUTH);
	}
	
    //初始化窗体
	public void initFrame() {
		//设置窗体的标题
		this.setTitle("计算器");
		//设置窗体大小不可改变
		this.setResizable(false);
		//设置界面置顶(就是页面不会别其他页面覆盖,界面始终在最上面)
        this.setAlwaysOnTop(true);
        //设置窗体的位置和大小,位置应该失效了,因为设置了居中
		//this.setBounds(300,150,400,500);
        //那还是改成setSize吧,设置窗体的大小就行了
        this.setSize(400,500);
		//居中
		this.setLocationRelativeTo(null);
		//设置窗体关闭按钮的动作作为退出
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//将显示器面板添加到窗体顶部
		this.getContentPane().add(viewPanel,BorderLayout.NORTH);
	}

遇到的问题:

问题1:上层的文本框的大小的宽度设置不了,然后一直没有变化。

解决:通过修改setColumns();调节成功了,这个我还不知道原理,有知道的希望大家可以告诉我呢,之前一直在修改setPreferredSize();然后没反应,修改流布局管理器也只是把空白的地方变多了。

问题2:底部宽度bottomLabel.setPreferredSize(new Dimension(10,0));用这个修改没反应。

解决:这个当然不会有反应,添加加底部的宽是10,高是0,结果当然不会显示,之前偷懒直接复制左右侧的导致没显示,所以应该是bottomLabel.setPreferredSize(new Dimension(0,10));才对。

用Java制作简单的计算器

事件的响应:

Java | swing 如何清空JTextField中的内容_如何清空jtextfield的数据_黄佳俊、的博客-CSDN博客情况描述:在一个JTextField中输入了数据,用一个按钮来清空里面的数据,要如何实现啊!首先要说的是:没有这个方法,clear,能设置JTextField内容为空但是可以这样巧妙地做到:使用jTextField.setText("");把内容替换为空字符串,来实现清空JTextField中的内容...https://blog.csdn.net/weixin_48419914/article/details/121470250解决java添加/点击JButton后键盘监听无效的问题_QASWINE的博客-CSDN博客问题:在点击JButton后,原来可以用的键盘操作用不了了原因:点击JButton,焦点在按钮上,原来的有键盘监听器的组件(JFrame、-JPanel)失去焦点解决方法:如果键盘监听器在frame上,添加 frame.requestFocus(),使他重获焦点。下面是一个例子: button.addActionListener(new ActionListener() { ...https://blog.csdn.net/qq_33831360/article/details/103280448Java 键盘事件无效的几种原因_mapcontrol.addkeylistener(_imonkeyi的博客-CSDN博客..https://blog.csdn.net/imonkeyi/article/details/86177348

 具体的方法就看方法内部的调用吧,有应该都有写方法的作用的,接下来就是确定事件源和监听源,我是打算通过键盘输入一些字符和通过鼠标点击按钮来实现。

1.确定事件源和监听源

事件源:JButton[][] buttons=new JButton[names.length][4];按钮,和自己本身框架

监听源:ActionListener,KeyListener

2.实现监听器的接口

//重写鼠标点击事件
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		JButton button =(JButton)e.getSource();//获得触发此次动作事件的按钮对象
		String buttonName =e.getActionCommand();//获得触发此次动作事件的按钮的标签文本
		
	
		if(buttonName.equals("X")) {
			//没有字符串之后就不能删除了
			if(sb.length()!=0) {
				sb.deleteCharAt(sb.length()-1);
				//textField.setText(output);//删除之后还需要立即显示一次,不然没有反应
			}
		}else if(buttonName.equals("R")){
			//就是把[0,length)的内容删除即可
			sb.delete(0, sb.length());
			//删除之后还需要立即显示一次,不然没有反应
			//textField.setText(output);
		}else if(buttonName.equals("=")) {
			//计算结果
			result();
		}else {
			sb.append(buttonName);
			//textField.setText(output);
		}
		//反正每次响应事件之后都要更新,干脆直接放在最后
		outPut();
		//要重新使框架获得焦点,这要写呢,不写就按下按钮之后键盘就没反应了
		if(buttonName.equals("=")) {
			//就是把[0,length)的内容删除即可
			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
		}
		this.requestFocus();
	}
            @Override
        	public void keyTyped(KeyEvent e) {
        		// TODO Auto-generated method stub
        		
        	}
        	//按着按键不松时调用
        	@Override
        	public void keyPressed(KeyEvent e) {
        		// TODO Auto-generated method stub
        	}
        	//按键松开后执行
        	@Override
        	public void keyReleased(KeyEvent e) {
        		// TODO Auto-generated method stub
        		//System.out.println("我被调用了啦");
        		int code = e.getKeyCode();
        		//输出每次按下的键盘按钮对应的code
        		//System.out.println(code);
        		//用键盘添加数字
        		//单纯输入数字,shift键没有被按下,不然就加减乘除无法被响应了
        		if(code>=48 && code<=57 && !e.isShiftDown()) {
        			sb.append((char)code);
        			//outPut();
        		}else if(code==56 && e.isShiftDown()) {
        			sb.append("*");
        			//outPut();
        		}else if(code==47 && !e.isShiftDown()) {
        			sb.append("/");
        		}else if(code==8) {//Backspace键
        			//删除最后的一个字符
        			sb.deleteCharAt(sb.length()-1);
        		}else if(code==53 && e.isShiftDown()) {
        			sb.append("%");
        		}else if(code==61 && e.isShiftDown()) {
        			sb.append("+");
        		}else if(code==61 && !e.isShiftDown()) {//"="
        			//计算结果
        			result();
        		}else if(code==45 && !e.isShiftDown()) {
        			sb.append("-");
        		}else if(code==46 && !e.isShiftDown()) {
        			sb.append(".");
        		}else if(code==10) {//Enter键
        			//计算结果
        			result();
        		}
        		//每次键盘输入之后都要更新,所以干脆就直接放判断最后
        		outPut();
        		//"="和"Enter"键
        		if(code==61 && !e.isShiftDown()||code==10) {
        			//就是把[0,length)的内容删除即可
        			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
        		}
        	}
        }

3.将事件源注册到监听器

public void buttonAction() {
		//按钮绑定动作事件,和自己绑定,自己实现的监听的方法
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				(buttons[row][col]).addActionListener(this);
			}
		}	
		//给整个界面添加键盘监听事件
        this.addKeyListener(new KeyListener() {
        	
        	@Override
        	public void keyTyped(KeyEvent e) {
        		// TODO Auto-generated method stub
        		
        	}
        	//按着按键不松时调用
        	@Override
        	public void keyPressed(KeyEvent e) {
        		// TODO Auto-generated method stub
        	}
        	//按键松开后执行
        	@Override
        	public void keyReleased(KeyEvent e) {
        		// TODO Auto-generated method stub
        		//System.out.println("我被调用了啦");
        		int code = e.getKeyCode();
        		//输出每次按下的键盘按钮对应的code
        		//System.out.println(code);
        		//用键盘添加数字
        		//单纯输入数字,shift键没有被按下,不然就加减乘除无法被响应了
        		if(code>=48 && code<=57 && !e.isShiftDown()) {
        			sb.append((char)code);
        			//outPut();
        		}else if(code==56 && e.isShiftDown()) {
        			sb.append("*");
        			//outPut();
        		}else if(code==47 && !e.isShiftDown()) {
        			sb.append("/");
        		}else if(code==8) {//Backspace键
        			//删除最后的一个字符
        			sb.deleteCharAt(sb.length()-1);
        		}else if(code==53 && e.isShiftDown()) {
        			sb.append("%");
        		}else if(code==61 && e.isShiftDown()) {
        			sb.append("+");
        		}else if(code==61 && !e.isShiftDown()) {//"="
        			//计算结果
        			result();
        		}else if(code==45 && !e.isShiftDown()) {
        			sb.append("-");
        		}else if(code==46 && !e.isShiftDown()) {
        			sb.append(".");
        		}else if(code==10) {//Enter键
        			//计算结果
        			result();
        		}
        		//每次键盘输入之后都要更新,所以干脆就直接放判断最后
        		outPut();
        		//"="和"Enter"键
        		if(code==61 && !e.isShiftDown()||code==10) {
        			//就是把[0,length)的内容删除即可
        			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
        		}
        	}
        });
	}public void buttonAction() {
		//按钮绑定动作事件,和自己绑定,自己实现的监听的方法
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				(buttons[row][col]).addActionListener(this);
			}
		}	
		//给整个界面添加键盘监听事件
        this.addKeyListener(new KeyListener() {
        	
        	@Override
        	public void keyTyped(KeyEvent e) {
        		// TODO Auto-generated method stub
        		
        	}
        	//按着按键不松时调用
        	@Override
        	public void keyPressed(KeyEvent e) {
        		// TODO Auto-generated method stub
        	}
        	//按键松开后执行
        	@Override
        	public void keyReleased(KeyEvent e) {
        		// TODO Auto-generated method stub
        		//System.out.println("我被调用了啦");
        		int code = e.getKeyCode();
        		//输出每次按下的键盘按钮对应的code
        		//System.out.println(code);
        		//用键盘添加数字
        		//单纯输入数字,shift键没有被按下,不然就加减乘除无法被响应了
        		if(code>=48 && code<=57 && !e.isShiftDown()) {
        			sb.append((char)code);
        			//outPut();
        		}else if(code==56 && e.isShiftDown()) {
        			sb.append("*");
        			//outPut();
        		}else if(code==47 && !e.isShiftDown()) {
        			sb.append("/");
        		}else if(code==8) {//Backspace键
        			//删除最后的一个字符
        			sb.deleteCharAt(sb.length()-1);
        		}else if(code==53 && e.isShiftDown()) {
        			sb.append("%");
        		}else if(code==61 && e.isShiftDown()) {
        			sb.append("+");
        		}else if(code==61 && !e.isShiftDown()) {//"="
        			//计算结果
        			result();
        		}else if(code==45 && !e.isShiftDown()) {
        			sb.append("-");
        		}else if(code==46 && !e.isShiftDown()) {
        			sb.append(".");
        		}else if(code==10) {//Enter键
        			//计算结果
        			result();
        		}
        		//每次键盘输入之后都要更新,所以干脆就直接放判断最后
        		outPut();
        		//"="和"Enter"键
        		if(code==61 && !e.isShiftDown()||code==10) {
        			//就是把[0,length)的内容删除即可
        			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
        		}
        	}
        });
	}

问题3:因为没有响应之后都要有对应的应答,有时候要输出,但是输入的按钮有些是含义多个字符的字符串,在计算和删除的时候删除的是单个的字符不是整个的字符串,比如sin输入的是“sin”删除只能删除最后的'n’。

解决:我这里是用到了HashMap来解决,在程序里面是单个的字符,输出是输出字符表示的字符串,这样删除计算等操作都方便了。

问题4:键盘输入对于*,+等的字符无法得到。

解决:我是通过 e.getKeyCode();来得到键盘输入的code,但是对于*和8是同一个code,都是56,不同的是shift键是否按下,之前是想写在 keyPressed里面来响应,但是感觉也实现不来,后面就是看到了e.isShiftDown();来判断shift键是否按下,也确实抱着试一试的态度,结果发现还真可以,就加上了e.isShiftDown();的判断。就解决了'*'和'8'有相同code的情况。

	//按钮里面的内容
	String [][]names= {
			{"**","ln","lg","clear"},
			{"sin","cos","tan","X"},
			{"PI","//","%","/"},
			{"7","8","9","*"},
			{"4","5","6","-"},
			{"1","2","3","+"},
			{"_/``","0",".","="}};
	//程序里面的内容
	String [][]target= {
			{"A","N","G","R"},
			{"S","C","T","X"},
			{"P","B","%","/"},
			{"7","8","9","*"},
			{"4","5","6","-"},
			{"1","2","3","+"},
			{"D","0",".","="}};    
    //用来对应文本框的输出,还是选择用HashMap来存储
	Map<String ,String>map=new HashMap<String,String>();
    //通过哈希表实现输出字符串和里面的字符串的不同标识
	public void Stringbind() {
		
		//map.put(getWarningString(), getName())
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				map.put(target[row][col], names[row][col]);
				//System.out.println("执行成功");
			}
		}
		//用来判断值有没有填写进去
		//System.out.println(map.size());
	}

问题5:在查找的时候输出的是null,不是目标的字符串。

解决:这我找了挺久的,最后还看了HashMap里面的元素有多少,发现是存进去的,问题出现在字符串“A”和'A'不是一样的东西,所以哈希表没找到。

输出是通过一个函数来实现

    //用来更新文本框输出的字符串
	StringBuffer sb=new StringBuffer();
	//用来对应文本框的输出,还是选择用HashMap来存储
	Map<String ,String>map=new HashMap<String,String>();
	//输出的字符串放这个里面,每次使用都需要清零哈
	String output="";
    //记录每次将输出的字符串
	public void outPut() {
		output="";
		for(int i=0;i<sb.length();i++) {
		//这我可能知道原因了,字符串"A"和'A'不一样
			output= output+map.get(String.valueOf(sb.charAt(i)));
		}
		//每次更新都要输出,我直接写到方法里面算了
		textField.setText(output);
	}

问题6:键盘的输入失灵。

解决:要通过聚焦,才能实现,调用this.setFocusable(true);

问题7:开始输入可以通过键盘输出,但是在按下面板中的按钮之后键盘无法输入。

解决:在每次按下按钮之后重新聚焦this.requestFocus();要重新使框架获得焦点,这要写呢,不写就按下按钮之后键盘就没反应了。

最后就是计算器功能实现的部分了,比较好实现的就是除‘=’号的按钮,直接添加到字符串里面,在最后打印就行。我这里采用的是StringBuffer因为要添加和更新什么的。

删除按钮和清空按钮分别就是删除字符串最后一个字符和删除字符串所有的字符。

//删除最后一个字符
if(sb.length()!=0) {
	sb.deleteCharAt(sb.length()-1);
	//textField.setText(output);//删除之后还需要立即显示一次,不然没有反应
}
//删除所有的字符,确定是范围是[0,length)
sb.delete(0, sb.length());

问题8:按下按钮之后没有显示删除。

解决:这个是因为没有显示,在程序中已经删除了,但是呢,用户看到是还没删除的样子,所以还是要更新一下输出。

计算:

java 实现字符串算式的计算_段593405572的博客-CSDN博客输入一个字符串(包括数字、小数点,加减乘除百分比),模拟计算器进行运算。 思路:按运算符优先级依次运算百分比、乘除、加减。遍历字符串,将运算符前或前后的数字字符转为double进行计算,计算后的结果替换原字符串中的子算式。 import java.util.Scanner;public class Main{public static double f(String s){double p = 0;//百分比计算for(int i = 0; i &...https://blog.csdn.net/d593405572/article/details/106713937

Java中角度和弧度的转换,三角函数,反三角函数_java角度转弧度-CSDN博客Java中角度和弧度的转换,三角函数,反三角函数https://blog.csdn.net/senxu_/article/details/126025606

接下来就是最后的计算环节了。

首先确定计算的优先级,我这里没有引入括号了,所以把lg,ln,sin,cos,tan,开根号都是和右边的操作数看成一个整体的。

字符串的运算就是通过运算符来分割,通过寻找到他的运算数,进行运算,把运算结果的字符串和运算前的字符串进行替换即可。

    //计算每次的结果
	public void result() {
		
		//对应关系
		//**--->A  ln--->N  lg--->G  sin--->S   cos--->C
		//tan--->T  PI--->P  //--->B  /``--->D
		//计算是按照优先级来的
		//PI不算运算,直接填进去吧
		//也不行,本来就是用一个符号来表示,这突然变成一长串数字,那还是运算的时候展开吧
		//展开PI
		try {
			pi();
			//ln,lg,sin,cos,tan,开根号的运算
			special();
			//乘方运算
			power();
			//乘除,整除,求余运算
			multiplyDivide();
			//加减计算
			addAndSubtract();
		}catch(Exception e) {
			//弹出警告的弹窗
			warning();
		}finally {
			System.out.println("今天又是元气满满的一天");
		}
	}

 PI就是一个替换,把PI在计算的时候换成Math.PI就行了,因为我用哈希表的初衷就是希望在程序中字符串是用一个的字符表示,所以PI我是在计算的时候才进行展开。

    //展开PI
	public void pi() {
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='P') {
				double res=Math.PI;
				String resString=res+"";
				//更新字符串
				sb=sb.replace(i, i+1, resString);
				i=resString.length()-1;
				continue;
			}
		}
	}

 这些我不是用什么名字,就用这个表示了,这些的特点就是只需要一个操作数即可。

所以只需要往右边找操作数,统计操作数的长度,把找到的数进行相应的修改和替换。

问题9:sin和tan不好用,用PI直接报错了。

解决:这个弧度制好像是越界了,我又没加括号,那还是Math.toRadians(num)输入角度制转成弧度制来运算吧。

//ln,lg,sin,cos,tan,开根号的运算
	public void special() {
		//都是用右边一个操作数的运算
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='N'||sb.charAt(i)=='G'||
					sb.charAt(i)=='S'||sb.charAt(i)=='C'||
					sb.charAt(i)=='T'||sb.charAt(i)=='D') {
				double num=0;
				int len=0;//记录字符串长度,之后还要进行字符串的替换呢
				//只需要应该一边的数字即可
				for(int j=i+1;j<sb.length();j++) {
					//是j不是i,咋又错在这里了
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-'||
							sb.charAt(j)=='A'||
							sb.charAt(j)=='N'||sb.charAt(j)=='G'||
							sb.charAt(j)=='S'||sb.charAt(j)=='C'||
							sb.charAt(j)=='T'||sb.charAt(j)=='D') {
						String s1=sb.substring(i+1,j);
						num=Double.parseDouble(s1);
						len=s1.length();
						break;
					}
					//找到最右边咯,中间没有运算符那也要停止了
					if(j==sb.length()-1) {
						//这边是到j+1哈,找错误找了半天
						//如果右边是一位的数字,就会导致运算是数是空
						//如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)
						String s1=sb.substring(i+1,j+1);
						num=Double.parseDouble(s1);
						len=s1.length();
						break;
					}
				}
				//进行运算
				//ln运算
				if(sb.charAt(i)=='N') {
					double res=Math.log(num);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//lg运算
				if(sb.charAt(i)=='G') {
					//换底公式
					double res=Math.log(num)/Math.log(10);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//sin运算
				if(sb.charAt(i)=='S') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.sin(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//cos运算
				if(sb.charAt(i)=='C') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.cos(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//tan运算
				if(sb.charAt(i)=='T') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.tan(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//开根号运算
				if(sb.charAt(i)=='D') {
					double res=Math.sqrt(num);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
			}
		}
	}

接下来就是两个操作数的啦。以乘方为例。

往左边和右边寻找操作数,左边的话需要考虑优先级低的操作字符以及字符串越界的情况,但是右边不仅是需要考虑这个还需要考虑本身这个字符。

就是往左边判断是(sb.charAt(j)=='*'||sb.charAt(j)=='/'||sb.charAt(j)=='%'||sb.charAt(j)=='B'||sb.charAt(j)=='+'||sb.charAt(j)=='-'),而右边判断是(sb.charAt(j)=='*'||sb.charAt(j)=='/'||sb.charAt(j)=='%'||sb.charAt(j)=='B'||sb.charAt(j)=='+'||sb.charAt(j)=='-'||sb.charAt(j)=='A'),这也要理解吧,因为字符串吧遍历是从左往右,右边还有这个‘A’没有判断,但是左边已经判断结束了。

    //乘方运算
	public void power(){
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='A') {
				double num1=0,num2=0;
				int len1=0,len2=0;//记录字符串长度,之后还要进行字符串的替换呢
				for(int j=i-1;j>=0;j--) {
					//得到第一个操作数,遇到加减乘除就停止了,相当于分隔了操作数
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-') {
						String s1=sb.substring(j+1,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
					//找到边界了,只能停止了咯
					if(j==0) {
						String s1=sb.substring(j,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
				}
				//往右边找第二个操作数,第二个操作数的话遇到乘除也需要提前终止,第一个不需要
				//因为如果第一个操作数有乘除这种符号,就已经提前终止了,只有第二个操作数才需要考虑
				for(int j=i+1;j<sb.length();j++) {
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-'||sb.charAt(j)=='A') {
						String s1=sb.substring(i+1,j);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
					//找到最右边咯,中间没有运算符那也要停止了
					if(j==sb.length()-1) {
						//这边是到j+1哈,找错误找了半天
						//如果右边是一位的数字,就会导致运算是数是空
						//如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)
						String s1=sb.substring(i+1,j+1);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
				}
				//进行运算
				double res=Math.pow(num1, num2);
				String resString=res+"";
				//更新字符串
				sb=sb.replace(i-len1, i+len2+1, resString);
				i=i-len1-1+resString.length();
				continue;
			}
		}
	}

加减乘除就和这个一样了。

问题10:会出现多个异常抛出的情况。

解答:循环里面操作数的判断,里面是sb.charAt(j)写成了sb.charAt(i);第二种就是在第二个操作数边界判断的时候String s1=sb.substring(i+1,j+1);写成了String s1=sb.substring(i+1,j);这也是直接复制前面的结果,因为之前停止是遇到运算符停止的,所以边界判断不需要考虑到j+1,但是这已经到底了,指针指向的就是数,如果右边是一位的数字,就会导致运算是数是空,如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)。

运算解决了,就是对异常的处理,之前的代码就有显示我加入了抛出异常的地方,如果错误是会出现一个弹窗。我还用finally来检验程序的健壮性。本来是对除数为0的情况加上了一个判断,因为是浮点数所以为0的判断条件设置成Math.abs(num2)<=1e-6,但是他没反应了,我干脆就直接不判断了这也算是异常,直接抛出弹出弹窗就行了。这还是方便一点。

注:这里有一个bug,因为操作数我最开始是设置成0,就导致如果只有一个数的时候也可以运算,比如“*1”是可以运行的,因为num1等于0,这个大家感兴趣可以自己完善一下哈

	//警告标签,放在弹窗里面
	final JLabel warningLabel=new JLabel();

    //警告,输入不合法的时候弹出
	public void warning() {
		JDialog jDialog=new JDialog();//创建弹窗对象
		jDialog.setTitle("警告");//设置弹窗标题,和Frame差不多,可能还要通过标签来提示
		jDialog.setSize(500,600);//设置弹窗的大小
		jDialog.setAlwaysOnTop(true);//让弹窗置顶
		jDialog.setLocationRelativeTo(null);//让弹窗居中
		jDialog.setModal(true);//弹窗不关闭则无法操作下面的界面
		
		//设置字体的类型,加粗,和大小
		warningLabel.setFont(new Font("Microsoft YaHei",Font.BOLD,30));
		//输出警告提示符
		warningLabel.setText("就是你小子在搞乱的是吧!!!");
		//标签的位置和大小
		warningLabel.setBounds(60,180,500,100);
		
		//这个也要取消布局管理器才行
		jDialog.getContentPane().setLayout(null);
		//往弹窗中添加标签
		jDialog.getContentPane().add(warningLabel);
		jDialog.setVisible(true);//让弹窗显示出来
		
	}

 警告的弹窗和内容都是自己设计的,弹窗就和框架一样,里面也是一个面板,我取消了布局,通过x,y坐标的方法进行移动。弹窗弹出如下所示。

用Java制作简单的计算器

问题11:在打印按钮的时候出现数组越界

因为整个数组不是矩阵,所以内存循环和外循环不是同一个边界值,内层循环的界限是用外层循环对应一维数组的长度作为边界值.

详细代码如下:



import java.awt.*;
import java.awt.event.*;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;


public class CalculatorFrame extends JFrame implements ActionListener{
	//主方法
	public static void main(String[] args) {
		CalculatorFrame cf=new CalculatorFrame();
	}
	//创建显示器面板,采用默认的流布局
	final JPanel viewPanel =new JPanel();
	//创建显示器
	final JTextField textField=new JTextField();
	//创建按钮面板
	final JPanel buttonPanel=new JPanel();
	//创建网络布局管理器对象
	final GridLayout gridLayout=new GridLayout(0,4);
	//按钮里面的内容
	String [][]names= {
			{"**","ln","lg","clear"},
			{"sin","cos","tan","X"},
			{"PI","//","%","/"},
			{"7","8","9","*"},
			{"4","5","6","-"},
			{"1","2","3","+"},
			{"_/``","0",".","="}};
	//程序里面的内容
	String [][]target= {
			{"A","N","G","R"},
			{"S","C","T","X"},
			{"P","B","%","/"},
			{"7","8","9","*"},
			{"4","5","6","-"},
			{"1","2","3","+"},
			{"D","0",".","="}};
	//创建按钮对象
	JButton[][] buttons=new JButton[names.length][4];
	//创建左侧的占位标签
	final JLabel leftLabel=new JLabel();
	//创建右侧的占位标签
	final JLabel rightLabel=new JLabel();
	//创建下侧的占位标签
	final JLabel bottomLabel=new JLabel();
	//存储计算结果
	double result=0;
	//用来更新文本框输出的字符串
	StringBuffer sb=new StringBuffer();
	//用来对应文本框的输出,还是选择用HashMap来存储
	Map<String ,String>map=new HashMap<String,String>();
	//输出的字符串放这个里面,每次使用都需要清零哈
	String output="";
	//警告标签,放在弹窗里面
	final JLabel warningLabel=new JLabel();
	
	public CalculatorFrame(){
		//初始化窗体
		initFrame();
		//初始化面板
		initPanel();
		//初始化哈希表里面的数据
		Stringbind();
		//绑定事件.键盘绑定也放在里面
		buttonAction();
		//窗体可见,放最后吧,不然里面的东西不会显示呢
		this.setVisible(true);
	}
	//初始化窗体
	public void initFrame() {
		//设置窗体的标题
		this.setTitle("计算器");
		//设置窗体大小不可改变
		this.setResizable(false);
		//设置界面置顶(就是页面不会别其他页面覆盖,界面始终在最上面)
        this.setAlwaysOnTop(true);
        //设置窗体的位置和大小,位置应该失效了,因为设置了居中
		//this.setBounds(300,150,400,500);
        //那还是改成setSize吧,设置窗体的大小就行了
        this.setSize(400,500);
		//居中
		this.setLocationRelativeTo(null);
		//设置窗体关闭按钮的动作作为退出
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//将显示器面板添加到窗体顶部
		this.getContentPane().add(viewPanel,BorderLayout.NORTH);
		//添加屏幕焦点,没有这个用键盘输入没反应埃
		this.setFocusable(true);
	}
	//初始化面板
	public void initPanel() {
		//初始化组件
		initModule();
		
		viewPanel.add(textField);
		viewPanel.setPreferredSize(new Dimension(100,80));
		this.getContentPane().add(viewPanel,BorderLayout.NORTH);
		
		
		buttonPanel.setLayout(gridLayout);//按钮面板采用网络布局
		this.getContentPane().add(buttonPanel,BorderLayout.CENTER);//将按钮面板添加到窗体中间
		//把按钮添加到按钮面板中,虽然可以和初始化按钮写一起,但是便于理解还是把他们分开写了
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				buttonPanel.add(buttons[row][col]);
			}
		}
		this.getContentPane().add(leftLabel,BorderLayout.WEST);
		this.getContentPane().add(rightLabel,BorderLayout.EAST);
		this.getContentPane().add(bottomLabel,BorderLayout.SOUTH);
	}
	
	//初始化组件
	public void initModule() {
		//初始化显示器相关数据
		textField.setEditable(false);//设置显示器不可编辑
		textField.setHorizontalAlignment(SwingConstants.RIGHT);
		textField.setColumns(35);//调节文本框的宽度
		textField.setPreferredSize(new Dimension(500,40));
	
		//初始化面板按钮
		gridLayout.setVgap(10);//设置组件的水平间距
		gridLayout.setHgap(10);//设置组件的垂直间距
		//初始化按钮对象
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				buttons[row][col]=new JButton(names[row][col]);//创建按钮
			}
		}
		//静态的初始化设置一些,把多个单词的给标识起来
		/*buttons[0][0].setActionCommand("A");//"**"
		buttons[0][1].setActionCommand("N");//"ln"
		buttons[0][2].setActionCommand("G");//"lg"
		buttons[0][3].setActionCommand("R");//clear
		buttons[1][0].setActionCommand("S");//sin
		buttons[1][1].setActionCommand("C");//cos
		buttons[1][2].setActionCommand("T");//tan
		buttons[2][0].setActionCommand("P");//PT
		buttons[2][1].setActionCommand("B");//"//"
		buttons[6][0].setActionCommand("D");//"+/-"
		*/
		//还是用循环全部绑定吧,自己一个一个绑代码灵活性不高
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				buttons[row][col].setActionCommand(target[row][col]);
			}
		}
		
		//设置左侧标签的宽度
		leftLabel.setPreferredSize(new Dimension(10,0));
		//设置右侧标签的宽度
		rightLabel.setPreferredSize(new Dimension(10,0));
		//设置底部标签的宽度,组件的有高度,可以没宽度,和两边相反
		bottomLabel.setPreferredSize(new Dimension(0,10));
	}
	//通过哈希表实现输出字符串和里面的字符串的不同标识
	public void Stringbind() {
		
		//map.put(getWarningString(), getName())
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				map.put(target[row][col], names[row][col]);
				//System.out.println("执行成功");
			}
		}
		//用来判断值有没有填写进去
		//System.out.println(map.size());
	}
	
	public void buttonAction() {
		//按钮绑定动作事件,和自己绑定,自己实现的监听的方法
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				(buttons[row][col]).addActionListener(this);
			}
		}	
		//给整个界面添加键盘监听事件
        this.addKeyListener(new KeyListener() {
        	
        	@Override
        	public void keyTyped(KeyEvent e) {
        		// TODO Auto-generated method stub
        		
        	}
        	//按着按键不松时调用
        	@Override
        	public void keyPressed(KeyEvent e) {
        		// TODO Auto-generated method stub
        	}
        	//按键松开后执行
        	@Override
        	public void keyReleased(KeyEvent e) {
        		// TODO Auto-generated method stub
        		//System.out.println("我被调用了啦");
        		int code = e.getKeyCode();
        		//输出每次按下的键盘按钮对应的code
        		//System.out.println(code);
        		//用键盘添加数字
        		//单纯输入数字,shift键没有被按下,不然就加减乘除无法被响应了
        		if(code>=48 && code<=57 && !e.isShiftDown()) {
        			sb.append((char)code);
        			//outPut();
        		}else if(code==56 && e.isShiftDown()) {
        			sb.append("*");
        			//outPut();
        		}else if(code==47 && !e.isShiftDown()) {
        			sb.append("/");
        		}else if(code==8) {//Backspace键
        			//删除最后的一个字符
        			sb.deleteCharAt(sb.length()-1);
        		}else if(code==53 && e.isShiftDown()) {
        			sb.append("%");
        		}else if(code==61 && e.isShiftDown()) {
        			sb.append("+");
        		}else if(code==61 && !e.isShiftDown()) {//"="
        			//计算结果
        			result();
        		}else if(code==45 && !e.isShiftDown()) {
        			sb.append("-");
        		}else if(code==46 && !e.isShiftDown()) {
        			sb.append(".");
        		}else if(code==10) {//Enter键
        			//计算结果
        			result();
        		}
        		//每次键盘输入之后都要更新,所以干脆就直接放判断最后
        		outPut();
        		//"="和"Enter"键
        		if(code==61 && !e.isShiftDown()||code==10) {
        			//就是把[0,length)的内容删除即可
        			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
        		}
        	}
        });
	}
	//重写鼠标点击事件
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		JButton button =(JButton)e.getSource();//获得触发此次动作事件的按钮对象
		String buttonName =e.getActionCommand();//获得触发此次动作事件的按钮的标签文本
		
	
		if(buttonName.equals("X")) {
			//没有字符串之后就不能删除了
			if(sb.length()!=0) {
				sb.deleteCharAt(sb.length()-1);
				//textField.setText(output);//删除之后还需要立即显示一次,不然没有反应
			}
		}else if(buttonName.equals("R")){
			//就是把[0,length)的内容删除即可
			sb.delete(0, sb.length());
			//删除之后还需要立即显示一次,不然没有反应
			//textField.setText(output);
		}else if(buttonName.equals("=")) {
			//计算结果
			result();
		}else {
			sb.append(buttonName);
			//textField.setText(output);
		}
		//反正每次响应事件之后都要更新,干脆直接放在最后
		outPut();
		//要重新使框架获得焦点,这要写呢,不写就按下按钮之后键盘就没反应了
		if(buttonName.equals("=")) {
			//就是把[0,length)的内容删除即可
			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
		}
		this.requestFocus();
	}
	//记录每次将输出的字符串
	public void outPut() {
		output="";
		for(int i=0;i<sb.length();i++) {
		//这我可能知道原因了,字符串"A"和'A'不一样
			output= output+map.get(String.valueOf(sb.charAt(i)));
		}
		//每次更新都要输出,我直接写到方法里面算了
		textField.setText(output);
	}
	//计算每次的结果
	public void result() {
		
		//对应关系
		//**--->A  ln--->N  lg--->G  sin--->S   cos--->C
		//tan--->T  PI--->P  //--->B  /``--->D
		//计算是按照优先级来的
		//PI不算运算,直接填进去吧
		//也不行,本来就是用一个符号来表示,这突然变成一长串数字,那还是运算的时候展开吧
		//展开PI
		try {
			pi();
			//ln,lg,sin,cos,tan,开根号的运算
			special();
			//乘方运算
			power();
			//乘除,整除,求余运算
			multiplyDivide();
			//加减计算
			addAndSubtract();
		}catch(Exception e) {
			//弹出警告的弹窗
			warning();
		}finally {
			System.out.println("今天又是元气满满的一天");
		}
	}
	//展开PI
	public void pi() {
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='P') {
				double res=Math.PI;
				String resString=res+"";
				//更新字符串
				sb=sb.replace(i, i+1, resString);
				i=resString.length()-1;
				continue;
			}
		}
	}
	//ln,lg,sin,cos,tan,开根号的运算
	public void special() {
		//都是用右边一个操作数的运算
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='N'||sb.charAt(i)=='G'||
					sb.charAt(i)=='S'||sb.charAt(i)=='C'||
					sb.charAt(i)=='T'||sb.charAt(i)=='D') {
				double num=0;
				int len=0;//记录字符串长度,之后还要进行字符串的替换呢
				//只需要应该一边的数字即可
				for(int j=i+1;j<sb.length();j++) {
					//是j不是i,咋又错在这里了
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-'||
							sb.charAt(j)=='A'||
							sb.charAt(j)=='N'||sb.charAt(j)=='G'||
							sb.charAt(j)=='S'||sb.charAt(j)=='C'||
							sb.charAt(j)=='T'||sb.charAt(j)=='D') {
						String s1=sb.substring(i+1,j);
						num=Double.parseDouble(s1);
						len=s1.length();
						break;
					}
					//找到最右边咯,中间没有运算符那也要停止了
					if(j==sb.length()-1) {
						//这边是到j+1哈,找错误找了半天
						//如果右边是一位的数字,就会导致运算是数是空
						//如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)
						String s1=sb.substring(i+1,j+1);
						num=Double.parseDouble(s1);
						len=s1.length();
						break;
					}
				}
				//进行运算
				//ln运算
				if(sb.charAt(i)=='N') {
					double res=Math.log(num);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//lg运算
				if(sb.charAt(i)=='G') {
					//换底公式
					double res=Math.log(num)/Math.log(10);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//sin运算
				if(sb.charAt(i)=='S') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.sin(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//cos运算
				if(sb.charAt(i)=='C') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.cos(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//tan运算
				if(sb.charAt(i)=='T') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.tan(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//开根号运算
				if(sb.charAt(i)=='D') {
					double res=Math.sqrt(num);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
			}
		}
	}
	//乘方运算
	public void power(){
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='A') {
				double num1=0,num2=0;
				int len1=0,len2=0;//记录字符串长度,之后还要进行字符串的替换呢
				for(int j=i-1;j>=0;j--) {
					//得到第一个操作数,遇到加减乘除就停止了,相当于分隔了操作数
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-') {
						String s1=sb.substring(j+1,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
					//找到边界了,只能停止了咯
					if(j==0) {
						String s1=sb.substring(j,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
				}
				//往右边找第二个操作数,第二个操作数的话遇到乘除也需要提前终止,第一个不需要
				//因为如果第一个操作数有乘除这种符号,就已经提前终止了,只有第二个操作数才需要考虑
				for(int j=i+1;j<sb.length();j++) {
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-'||sb.charAt(j)=='A') {
						String s1=sb.substring(i+1,j);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
					//找到最右边咯,中间没有运算符那也要停止了
					if(j==sb.length()-1) {
						//这边是到j+1哈,找错误找了半天
						//如果右边是一位的数字,就会导致运算是数是空
						//如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)
						String s1=sb.substring(i+1,j+1);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
				}
				//进行运算
				double res=Math.pow(num1, num2);
				String resString=res+"";
				//更新字符串
				sb=sb.replace(i-len1, i+len2+1, resString);
				i=i-len1-1+resString.length();
				continue;
			}
		}
	}
	//乘除,整除,求余运算
	public void multiplyDivide() {
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='*'||sb.charAt(i)=='/'||
					sb.charAt(i)=='%'||sb.charAt(i)=='B') {
				double num1=0,num2=0;
				int len1=0,len2=0;//记录字符串长度,之后还要进行字符串的替换呢
				for(int j=i-1;j>=0;j--) {
					//得到第一个操作数,遇到加减就停止了,相当于分隔了操作数
					if(sb.charAt(j)=='+'||sb.charAt(j)=='-') {
						String s1=sb.substring(j+1,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
					//找到边界了,只能停止了咯
					if(j==0) {
						String s1=sb.substring(j,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
				}
				//往右边找第二个操作数,第二个操作数的话遇到乘除也需要提前终止,第一个不需要
				//因为如果第一个操作数有乘除这种符号,就已经提前终止了,只有第二个操作数才需要考虑
				for(int j=i+1;j<sb.length();j++) {
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-') {
						String s1=sb.substring(i+1,j);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
					//找到最右边咯,中间没有运算符那也要停止了
					if(j==sb.length()-1) {
						//这边是到j+1哈,找错误找了半天
						//如果右边是一位的数字,就会导致运算是数是空
						//如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)
						String s1=sb.substring(i+1,j+1);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
				}
				//进行运算
				if(sb.charAt(i)=='*') {
					double res=num1*num2;
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					i=i-len1-1+resString.length();
					continue;
				}
				if(sb.charAt(i)=='/') {
					//除数不能为0,有异常抛出的弹窗了,就去掉这个了
					/*if(Math.abs(num2)<=1e-6) {
						System.out.println("输出警告");
						continue;
					}*/
					double res=num1/num2;
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					i=i-len1-1+resString.length();
					continue;
				}
				if(sb.charAt(i)=='%') {
					//整数才能求余,第二个操作数也不能为0
					/*if(Math.abs(num2)<=1e-6) {
						System.out.println("输出警告");
						continue;
					}*/
					//是求余%
					double res=(int)num1%(int)num2;
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					i=i-len1-1+resString.length();
					continue;
				}
				if(sb.charAt(i)=='B') {
					//整数的运算
					//除数不能为0
					/*if(Math.abs(num2)<=1e-6) {
						System.out.println("输出警告");
						continue;
					}*/
					double res=(int)num1/(int)num2;
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					i=i-len1-1+resString.length();
					continue;
				}
			}
		}
	}
	//加减运算
	public void addAndSubtract() {
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='+'||sb.charAt(i)=='-') {
				//运算符两边的操作数
				double num1=0,num2=0;
				//记录两个操作数的字符串长度
				int len1=0,len2=0;
				//寻找第一个操作数
				for(int j=i-1;j>=0;j--) {
					if(j==0) {
						String s1=sb.substring(j,i);
						//得到第一个操作数
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
				}
				for(int j=i+1;j<sb.length();j++) {
					if(sb.charAt(j)=='+'||sb.charAt(j)=='-') {
						String s1=sb.substring(i+1,j);
						//得到第二个操作数
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
					if(j==sb.length()-1) {
						String s1=sb.substring(i+1,j+1);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
				}
				//进行加运算
				if(sb.charAt(i)=='+') {
					double res=num1+num2;
					//String s2=sb.substring(i-len1,i+len2+1);
					//String s3=res+ "";
					//sb=sb.replace(s2, s3);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					
					i=i-len1-1+resString.length();
					continue;
				}
				//进行减运算
				if(sb.charAt(i)=='-') {
					double res=num1-num2;
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					i=i-len1-1+resString.length();
					continue;
				}
			}
		}
	}
	//警告,输入不合法的时候弹出
	public void warning() {
		JDialog jDialog=new JDialog();//创建弹窗对象
		jDialog.setTitle("警告");//设置弹窗标题,和Frame差不多,可能还要通过标签来提示
		jDialog.setSize(500,600);//设置弹窗的大小
		jDialog.setAlwaysOnTop(true);//让弹窗置顶
		jDialog.setLocationRelativeTo(null);//让弹窗居中
		jDialog.setModal(true);//弹窗不关闭则无法操作下面的界面
		
		//设置字体的类型,加粗,和大小
		warningLabel.setFont(new Font("Microsoft YaHei",Font.BOLD,30));
		//输出警告提示符
		warningLabel.setText("就是你小子在搞乱的是吧!!!");
		//标签的位置和大小
		warningLabel.setBounds(60,180,500,100);
		
		//这个也要取消布局管理器才行
		jDialog.getContentPane().setLayout(null);
		//往弹窗中添加标签
		jDialog.getContentPane().add(warningLabel);
		jDialog.setVisible(true);//让弹窗显示出来
		
	}
}

 总结:

这写下来还是写了挺长的时间了,目前还是比较满意的,因为是刚学JAVA语言,所以有很多地方都没太弄懂,有错误的地方,希望大家能够指正。对于计算器的功能编写其实还是能够添加很多功能也可以把Math.E添加进去,进行其他运算,大家可以根据自己的需求进行编写。写这个我的感受就是就是把我学的东西都用到了哈希表,异常抛出,控件都用上了,我对于他有一个比较清晰的认识,他要实现什么功能,虽然看着简单,但是卡在了很多地方,还有到处找资料来分析他的原因,尽管是有点简陋,我还加入了一些自己的东西,按下Backspace键和Enter键也有对应的响应,这也是努力的结果,希望未来越来越好吧。

6月14日,给按钮添加颜色

这个的话看自己想怎么弄,如果有规律的话可以尝试用循环,不然就需要一个个的调整,建议这个添加到initModule方法里面,这个是我专门用来设计组件信息的方法。(下面是一个示范的案例)

buttons[0][0].setBackground(Color.red);//给第一个按钮添加红色背景的按钮

用Java制作简单的计算器

6月15日,调节按钮中字体的大小。

在创建按钮的时候,给字体统一设置。对原始程序中的修改如下。

 //初始化按钮对象
 for(int row=0;row<names.length;row++) {
     for(int col=0;col<names[row].length;col++) {
        buttons[row][col]=new JButton(names[row][col]);//创建按钮
        //设置字体的类型,是否加粗和字体的大小
        buttons[row][col].setFont(new Font("Microsoft YaHei",Font.BOLD,20));
      }
 }

用Java制作简单的计算器

 文章来源地址https://www.toymoban.com/news/detail-472444.html

到了这里,关于用Java制作简单的计算器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android Studio制作一个简单的计算器APP

    虽然现在我们日常生活中很少用到计算器,但是第一次尝试在Android Studio上做一个计算器 程序设计步骤: (1)在布局文件中声明编辑文件框EditText,按钮Button等组件。 (2)在MainActivity中获取组件实例。 (3)通过swtich函数,判断输入的内容,并进行相应操作,通过getText()获

    2024年02月11日
    浏览(49)
  • Java编写简单计算器

    本文用 Java 的 swing 来实现一个简单计算器,主要内容为图形用户界面GUI的实现以及运算表达式核心算法的设计编写。 程序运行环境为Windows10 ,编译环境为IntelliJ IDEA Community Edition 2022.2.3 一、具体功能: 1、:输入,输出  输入:允许输入带有括号的完整计算式(例 8*(4-95)

    2024年02月04日
    浏览(41)
  • Java——一个简单的计算器程序

      该代码是一个简单的计算器程序,使用了Java的图形化界面库Swing。具体分析如下: 导入必要的类和包: 代码中导入了用于创建图形界面的类和接口,以及其他必要的类。 定义Calculator类: 代码中定义了一个名为Calculator的类,继承了JFrame类,并实现了ActionListener接口。Calc

    2024年02月04日
    浏览(49)
  • Java设计一个简单的计算器程序

    计算器是一种常见的工具,用于进行基本数学运算。在计算机科学中,我们可以使用编程语言来模拟和实现一个计算器程序。本文将基于Java语言,设计并实现一个简单的计算器程序。 1. 需求分析 在设计计算器程序之前,我们需要明确程序的需求。本文设计的计算器程序应满

    2024年02月05日
    浏览(58)
  • Java实现简单计算器(GUI)页面(适合入门)

    使用Java Swing的GUI图形用户界面编程设计并编写一个简易计算器程序,用户通过鼠标或者键盘操作输入参加运算的数值和运算符,要求能进行简单的四则运算。

    2024年02月12日
    浏览(56)
  • Qt制作计算器

    运用数据队列中的栈知识,使用Qt制作简易的计算器 ①支持中缀表达式的基本四则运算 ②支持软(软件自带键盘),硬(实体键盘)键盘均可操作,并且按键时触发小特效 ③支持查看历史记录 将用户输入的表达式分解为 运算符 和 操作数 两类 运算符:\\\"+\\\", \\\"-\\\", \\\"*\\\", \\\"/\\\", \\\"(\\\", \\\")\\\" 操

    2024年02月08日
    浏览(78)
  • C# 制作简易计算器

    前言:环境是vs 2022 1、打开vs2022后,右边导航栏选择创建新项目。  2、选择Windows窗体应用(.net  Framework)  3、进入配置新项目界面(项目名称和位置可自行修改)点击创建  4、窗体From1即为我们要要编辑的位置  5、在窗体中添加对应的工具 6、并在对应的属性窗口为其修改

    2024年02月08日
    浏览(50)
  • MFC基于对话框——仿照Windows计算器制作C++简易计算器

    目录 一、界面设计 二、设置成员变量 三、初始化成员变量  四、初始化对话框 ​五、添加控件代码 1.各个数字的代码(0~9) 2.清除功能的代码 3.退格功能的代码 4.加减乘除功能的代码 5.小数点功能的代码 6.正负号功能的代码 7.等于功能的代码 六、源码领取方式 制作好之后

    2024年02月05日
    浏览(70)
  • 用python制作一个简易计算器

    这是一个用Python制作简单计算器的教程。你可以根据需要进行更多的改进,例如添加其他运算符或功能。 首先,我们需要创建一个简单的用户界面,用于显示计算器的按键和结果。在Python中,我们可以使用 tkinter 库来创建图形用户界面。创建一个新的Python文件,并将其命名为

    2024年02月11日
    浏览(45)
  • Qt 制作一个简易的计算器

    1.通过UI界面封装出计算器的大致模型 进入设计页面后,左侧会有各种控件,可以将他们拖拽到你想编辑的窗口中,我们要做的是计算器,所以只用到很少几个控件,我们最主要用到Push Button这个控件来做我们计算器的按钮,lineEdit显示数字,我们可以将它拖拽到窗口,然后就

    2024年02月05日
    浏览(126)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包