Make a simple calculator in Java

This article mainly provides ideas. Of course, the source code is also provided at the end of the article.

The code also took several days to write. The important thing to understand is that you don’t just copy and paste and hand in the assignment.

Please indicate the source when reprinting and respect the fruits of the author's work.

Table of contents

Interface design:

Response to event:

Calculation

The detailed code is as follows:

 Summarize:


To make a simple calculator, the first step is to design the interface, and then implement its functions.

The realization of the event is roughly divided into the following steps.

  1. Determine event sources and listening sources
  2. Implement the listener interface
  3. Register the event source to the listener

Then let's start writing the code together. I divided it into several distributions to write the function. Finally, I have the final code, which can be run directly. It should be noted that if you paste it directly, the class name and file name must be the same.

Interface design:

There should be a text box at the top and many buttons in the middle. The big frame here uses the BorderLayout class layout manager, and its NORTH (top of the container) is added with a FlowLayout class layout manager. Inside the FlowLayout It is a text box, and CENTER (the middle of the container) is added with a GirdLayout class layout manager to form a grid of buttons, WEST (the left side of the container), EAST (the right side of the container), SOUTH (the bottom of the container), These are taken up by adding a blank label to make the interface look better.

	//创建显示器面板,采用默认的流布局
	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);
	}

Problems encountered:

Question 1: The size and width of the upper text box cannot be set, and then it remains unchanged.

Solution: The adjustment was successful by modifying setColumns();. I don’t know the principle yet. If anyone knows, I hope you can tell me. I have been modifying setPreferredSize(); before and then there was no response. Modifying the flow layout manager only changed the blank There are more places.

Question 2: The bottom width bottomLabel.setPreferredSize(new Dimension(10,0)); does not respond to this modification.

Solution: Of course this will not work. Add the width of the bottom to 10 and the height to 0. Of course the result will not be displayed. I was too lazy to directly copy the left and right sides and it was not displayed, so it should be bottomLabel.setPreferredSize(new Dimension(0, 10)); That’s right.

Event response:

Java | swing How to clear the content in JTextField_How to clear the data of jtextfield_Huang Jiajun's blog-CSDN blogSituation description: Data is entered in a JTextField, using a button to clear the data inside, how to achieve it! The first thing I want to say is: there is no such method, clear, that can set the content of JTextField to empty, but it can be done cleverly: use jTextField.setText(""); to replace the content with an empty string to clear the JTextField. The content...https://blog.csdn.net/weixin_48419914/article/details/121470250Solution to the problem that keyboard monitoring is invalid after adding/clicking JButton in Java Problem_QASWINE's Blog-CSDN BlogProblem: After clicking JButton, the original keyboard operations that can be used cannot be used. Reason: Clicking JButton, the focus is on the button, and there is a keyboard listener. The component (JFrame, -JPanel) loses focus. Solution: If the keyboard listener is on the frame, add frame.requestFocus() to regain focus. Here is an example: button.addActionListener(new ActionListener() { ...https://blog.csdn.net/qq_33831360/article/details/103280448Several reasons why Java keyboard events are invalid_mapcontrol.addkeylistener(_imonkeyi's blog-CSDN blog..https://blog.csdn.net /imonkeyi/article/details/86177348

 The specific method depends on the calls inside the method. There should be methods for writing. The next step is to determine the event source and monitoring source. I plan to enter some characters through the keyboard and click the button with the mouse.

1. Determine the event source and listening source

Event source: JButton[][] buttons=new JButton[names.length][4]; button, and its own frame

Listening source: ActionListener, KeyListener

2. Implement the listener interface

//重写鼠标点击事件
	@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. Register the event source to the listener

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());//结果出来之后就是重新输入计算下一个
        		}
        	}
        });
	}

Question 3: Because there must be a corresponding response after no response, sometimes it needs to be output, but some of the input buttons contain strings with multiple characters. During calculation and deletion, a single character is deleted, not the entire string. , for example, if the sin input is "sin", deletion can only delete the last 'n'.

Solution: I used HashMap to solve the problem here. In the program, it is a single character, and the output is a string represented by the output character. This makes operations such as deletion and calculation convenient.

Question 4: Keyboard input cannot be obtained for characters such as *, +, etc.

Solution: I used e.getKeyCode(); to get the code entered by the keyboard, but * and 8 are the same code, both 56. The difference is whether the shift key is pressed. Previously, I wanted to write it in keyPressed to respond. , but I felt it couldn't be implemented. Later I saw e.isShiftDown(); to determine whether the shift key was pressed. I really wanted to give it a try, but found that it really worked, so I added e.isShiftDown( ); judgment. This solves the situation where '*' and '8' have the same 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());
	}

Question 5: When searching, the output is null, not the target string.

Solution: I have been looking for this for a long time. Finally, I looked at how many elements there were in the HashMap and found that they were stored. The problem was that the string "A" and 'A' were not the same thing, so Hash table not found.

The output is achieved through a function

    //用来更新文本框输出的字符串
	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);
	}

Problem 6: The keyboard input fails.

Solution: This can only be achieved by focusing, call this.setFocusable(true);

Question 7: The input can be output through the keyboard at the beginning, but the keyboard cannot be input after pressing the button in the panel.

Solution: Refocus this.requestFocus() after each button press; to refocus the frame, you need to write this. If you press the button without writing, the keyboard will become unresponsive.

The last part is the implementation of the calculator function. The easier thing to implement is to add the button except the '=' sign directly to the string and print it at the end. I use StringBuffer here because I need to add and update it.

The delete button and clear button are to delete the last character of the string and delete all the characters of the string respectively.

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

Question 8: Delete is not displayed after pressing the button.

Solution: This is because it is not displayed and has been deleted in the program. However, the user sees that it has not been deleted, so the output still needs to be updated.

calculate:

Java realizes the calculation of string calculation_Duan 593405572's blog-CSDN blogInput a string (including numbers, decimal points, addition, subtraction, multiplication and division of percentages), and simulate the calculator to perform calculations . Idea: Operate percentages, multiplication, division, addition and subtraction in order according to operator precedence. Traverse the string, convert the numeric characters before or after the operator into double for calculation, and replace the sub-calculation in the original string with the calculated result. import java.util.Scanner;public class Main{public static double f(String s){double p = 0;//Percentage calculation for(int i = 0; i &...https://blog.csdn.net/d593405572/article/details/106713937

Conversion of angles and radians in Java, trigonometric functions, inverse trigonometric functions_java angle to radian-CSDN BlogConversion of angles and radians in Java, trigonometric functions, inverse trigonometric functions https://blog.csdn.net/senxu_/article/details/126025606

Next comes the final calculation step.

First determine the priority of the calculation. I have not introduced parentheses here, so lg, ln, sin, cos, tan, and the root sign are regarded as a whole with the operand on the right.

The operation of a string is to divide it through operators. By finding its operands, performing the operation, and replacing the string of the operation result with the string before the operation.

    //计算每次的结果
	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 is a replacement. Just replace PI with Math.PI when calculating. Because my original intention of using the hash table is to use one character to represent the string in the program, so I only use PI when calculating. Expand.

    //展开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;
			}
		}
	}

 I don’t use any names for these, just use this to represent them. The characteristic of these is that they only require one operand.

So you only need to look for the operand to the right, count the length of the operand, and modify and replace the found number accordingly.

Question 9: Sin and tan are not easy to use, and an error is reported directly when using PI.

Solution: This radian system seems to be out of bounds, and I didn’t add brackets, so let’s use Math.toRadians(num) to convert the angle system into radian system for calculation.

//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;
				}
			}
		}
	}

Next comes the two operands. Take exponentiation as an example.

Look for operands on the left and right. On the left, you need to consider low-priority operation characters and string out-of-bounds situations, but on the right, you need to consider not only this but also the character itself.

is to judge to the left (sb.charAt(j)=='*'||sb.charAt(j)=='/'||sb .charAt(j)=='%'||sb.charAt(j)=='B'||sb.charAt(j)=='+& #39;||sb.charAt(j)=='-'), and the judgment on the right is (sb.charAt(j)=='*'||sb. charAt(j)=='/'||sb.charAt(j)=='%'||sb.charAt(j)=='B 39;||sb.charAt(j)=='+'||sb.charAt(j)=='-'||sb.charAt(j)=='A'), you have to understand this, because the string traversal is from left to right, and there is this' on the right A' has not been judged, but the judgment on the left has ended.

    //乘方运算
	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;
			}
		}
	}

Addition, subtraction, multiplication and division are just like this.

Question 10: Multiple exceptions may be thrown.

Answer: When judging the operands in the loop, sb.charAt(j) is written as sb.charAt(i); the second one is when judging the boundary of the second operand, String s1=sb.substring(i+1 , j+1); written as String s1=sb.substring(i+1,j); This is also a direct copy of the previous result, because the previous stop was stopped when an operator was encountered, so the boundary judgment does not need to take j+ into account 1. But this is the end. The pointer points to a number. If the right side is a one-digit number, the operation will cause the number to be empty. If the right side is a multi-digit number, then the rightmost number will not participate in the operation, so Requires [i+1,j+1).

After the operation is solved, it is time to handle the exception. The previous code shows that I have added the place where the exception is thrown. If there is an error, a pop-up window will appear. I also use finally to test the robustness of the program. Originally, I added a judgment for the case where the divisor is 0. Because it is a floating point number, the judgment condition for 0 is set to Math.abs(num2)<=1e-6, but he didn't respond, so I simply stopped it. After judging that this is an abnormality, just throw a pop-up window. This is still more convenient.

Note: There is a bug here, because I initially set the operand to 0, which means that it can be operated even if there is only one number. For example, "*1" can be run because num1 is equal to 0. If you are interested, you can improve this yourself.

	//警告标签,放在弹窗里面
	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);//让弹窗显示出来
		
	}

 The pop-up window and content of the warning are all designed by myself. The pop-up window is just like the frame, and there is also a panel inside. I canceled the layout and moved it through the x, y coordinate method. The pop-up window pops up as shown below.

Question 11: Array out of bounds when printing button

Because the entire array is not a matrix, the memory loop and the outer loop do not have the same boundary value. The limit of the inner loop uses the length of the one-dimensional array corresponding to the outer loop as the boundary value.

The detailed code is as follows:



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);//让弹窗显示出来
		
	}
}

 Summarize:

It has taken me a long time to write this down, and I am quite satisfied with it now. Because I have just learned the JAVA language, I don’t quite understand many things. I hope you can correct me if there are any mistakes. In fact, you can add many functions to the calculator function writing. You can also add Math.E to perform other calculations. You can write it according to your own needs. My feeling when writing this is that I have used everything I learned about hash tables, exception throwing, and controls. I have a relatively clear understanding of it and what functions it wants to achieve. Although it looks simple, But I got stuck in many places, and I searched for information everywhere to analyze the reasons. Although it was a bit crude, I also added some of my own things. Pressing the Backspace key and the Enter key also had corresponding responses. This is also the result of hard work. Hope the future will get better and better.

June 14, add color to buttons

It depends on how you want to do this. If there is a pattern, you can try to use a loop, otherwise you need to adjust it one by one. It is recommended to add this to the initModule method. This is what I A method specifically designed to design component information. (The following is a demonstration case)

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

On June 15, adjust the font size in the button.

When creating buttons, set the font uniformly. The modifications to the original program are as follows.

 //初始化按钮对象
 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));
      }
 }

 

Guess you like

Origin blog.csdn.net/weixin_64066303/article/details/130383385