一.UI界面的布置

窗体中放置三个JPanel面板,第一个面板放数字与操作符组件(0-9,+ - * / . =),4*4网格布局,置于窗体中部;第二个面板放文本框,置于顶部;第三个面板放 清空 按钮与 历史记录 按钮,置于底部。

窗体为边界布局。

按钮上的数字/操作符使用数组存储,一个for循环就能创建完按钮并添加到JPanel面板中。

String[] butname= {"7","8","9","+","4","5","6","-","1","2","3","*",".","0","=","/"};
for (int i=0;i<butname.length;i++)
{
	JButton button=new JButton(butname[i]);
        //使用匿名内部类添加监听事件
	button.addActionListener(new ActionListener(){
               //重写 actionPerformed()方法
        });
	panel1.add(button);
}
frame.add(panel1,BorderLayout.CENTER);

文本框的创建

JTextField result_Jtf;
result_Jtf=new JTextField(30);
result_Jtf.setHorizontalAlignment(JTextField.RIGHT);//右对齐
result_Jtf.setEditable(false);//文本框禁止编辑

panel2.setLayout(new BorderLayout());//边界布局
panel2.add(result_Jtf);//文本框置于panel2组件中

frame.add(panel2,BorderLayout.NORTH);//置于顶部

清空与历史记录 按钮

设置了一个Hiatory数组用于存储记录,仅能显示最近五条,每次显示一条。

count_H变量记录按下该按钮的次数,作为数组的下标

JButton CE=new JButton("CE");
JButton history=new JButton("历史记录");
panel3.add(CE);
panel3.add(history);
frame.add(panel3, BorderLayout.SOUTH);

二.添加事件监听器

str存储表达式。

所有操作符的按钮除=之外被按下时,都添加其代表操作符到str中,并且添加时在其前后加上空格,便于用split()分割成子串。

if (actionbut.equals("+")||actionbut.equals("-")||actionbut.equals("*")||actionbut.equals("/"))
{
	str=str+" "+actionbut+" ";
}

数字则直接添加到str中。

str=str+actionbut;

按下=号时,对表达式求值,将结果打印到文本框中,对按下等号的次数计数,因为只显示最近五条记录,所以次数还要对5取模,让它的范围在[0,4]之间,然后把str存入到历史记录的数组中,最后将str置空。

str=str+actionbut+calculate(str);//calculate()为表达式求值函数
result_Jtf.setText(str);//打印到文本框中
count_equ=count_equ%5;//仅保存最近五条记录
History[count_equ]=str;//存到历史记录数组中
count_equ++;
str=" ";
flag=0;

其中,对表达式求值,具体操作如下:

使用split()分割str,并将子串存到一个String数组中。(为什么不用double而用Double,当然是Double有很多方法可以使用呀,比如我们等下就要用到的parseDouble(),它可以把String转成Double类型,而Double虽然是个类,但可以直接与基本数据类型进行四则运算,后面就可以直接计算啦)

创建一个栈,数据为Double型的,存储所有的数字。

由于str的初始值为" ",也不知道为什么分割值没把它去掉,反正它就占据了数组第一位的位置(也就是下标为0)。所以导致了数组中下标为奇数的是数字,偶数是操作符。因此我们把下标为1的元素先丢进栈中。

for循环的i从2开始。判断i是否为偶数,是则对该位上的操作符进行判断。

+:直接将后一位数字(Arr[i+1])入栈

-:取负后入栈

*:将栈顶元素出栈,与Arr[i+1]进行乘运算后将结果入栈

/:将栈顶元素出栈,将进行除运算的结果入栈

最后将栈中的所有数字相加,把结果转为字符串形式返回,与原str一起打印到文本框中。

public String calculate(String str) 
{
	String[] comput=str.split(" ");//分割操作符与数字
	Stack<Double> stack=new Stack<Double>();//存储数据
	stack.push(Double.parseDouble(comput[1]));
	for (int i=2;i<comput.length;i++)
	{
	    if (i%2==0)
	    {
		if (comput[i].equals("+"))
		{
		    stack.push(Double.parseDouble(comput[i+1]));//把字符串转成数字
		}
		if (comput[i].equals("-"))
		{
		    stack.push(-Double.parseDouble(comput[i+1]));
	        }
		if (comput[i].equals("*"))
		{
		    Double m=stack.peek();
		    stack.pop();
		    Double n=Double.parseDouble(comput[i+1]);//把*前后两个数相乘再压栈
		    stack.push(m*n);
		}
		if (comput[i].equals("/"))
		{
		    Double m=stack.peek();
		    stack.pop();
		    Double n=Double.parseDouble(comput[i+1]);
		    stack.push(m/n);
		}
	    }
	}
	double sum=0;
	while (!stack.isEmpty())
	{
	    sum=sum+stack.peek();
	    stack.pop();
	}
	String result=String.valueOf(sum);//转换成字符串型
	return result;
}

关于程序的一点小问题:窗体出现时窗口一片空白,人为放大或缩小后才会显示界面。也不知道为啥,明明设了窗体可见。

2019.3.4

原因是我设置可见那句代码放得太前面了,应该放在后面。

 

一点想法:文本框只能显示一行,如果要显示历史记录的话,使用文本域是比较好的,由于历史记录是完成基本运算后额外添加的功能,然后,改成文本域的话,要改动好多地方,就懒得再动了emmmm。

以上。

完整代码如下

/*
在未输入数字之前,不能输入操作符
*/
package calculator;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Stack;
public class calculator 
{
	String str=" ";//文本框的内容
	JFrame frame;
	JTextField result_Jtf;
	JPanel panel1,panel2,panel3;
	String[] History=new String[5];
	int count_H=0;//按下 历史记录 的次数
	int count_equ=0;//按下 = 的次数
	
	public calculator ()
	{
		frame=new JFrame("Calculator");
		frame.setLayout(new BorderLayout());
		frame.setLocation(300,200);
		frame.setSize(450,300);
		frame.setVisible(true);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		result_Jtf=new JTextField(30);
		result_Jtf.setHorizontalAlignment(JTextField.RIGHT);//右对齐
		result_Jtf.setEditable(false);//文本框禁止编辑
		
		panel3=new JPanel();
		panel3.setLayout(new GridLayout(1,2,5,5));
		JButton CE=new JButton("CE");
		JButton history=new JButton("历史记录");
		panel3.add(CE);
		panel3.add(history);
		frame.add(panel3, BorderLayout.SOUTH);
		
		panel1=new JPanel();
		panel2=new JPanel();
		panel1.setLayout(new GridLayout(4,4,5,5));//4*4网格布局
		panel2.setLayout(new BorderLayout());//边界布局
		panel2.add(result_Jtf);//文本框置于panel2组件中
		
		CE.addActionListener(new ActionListener() {
		        public void actionPerformed(ActionEvent e)
		        {
		                str=" ";
		                result_Jtf.setText(str);
		        }
		});
		history.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e)
			{
				count_H=count_H%5;//只能显示最近五条记录
				String his_str=History[count_H];
				result_Jtf.setText(his_str);
				count_H++;
				str=" ";
			}
		});
		
		String[] butname= {"7","8","9","+","4","5","6","-","1","2","3","*",".","0","=","/"};
		for (int i=0;i<butname.length;i++)
		{
			JButton button=new JButton(butname[i]);
			button.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e)
				{
					String actionbut=e.getActionCommand();
					int flag=1;
					if (actionbut.equals("+")||actionbut.equals("-")||actionbut.equals("*")||actionbut.equals("/"))
					{
						str=str+" "+actionbut+" ";
					}
					else if (actionbut.equals("="))
					{
						str=str+actionbut+calculate(str);
						result_Jtf.setText(str);
						count_equ=count_equ%5;//仅保存最近五条记录
						History[count_equ]=str;
						count_equ++;
						str=" ";
						flag=0;
					}
					else
					{
						str=str+actionbut;
					}
					if (flag==1)
						{
							result_Jtf.setText(str);
						}
				}
				public String calculate(String str) 
				{
					String[] comput=str.split(" ");//分割操作符与数字
					Stack<Double> stack=new Stack<Double>();//存储数据
					stack.push(Double.parseDouble(comput[1]));
					for (int i=2;i<comput.length;i++)
					{
						if (i%2==0)
						{
							if (comput[i].equals("+"))
							{
								stack.push(Double.parseDouble(comput[i+1]));//把字符串转成数字
							}
							if (comput[i].equals("-"))
							{
								stack.push(-Double.parseDouble(comput[i+1]));
							}
							if (comput[i].equals("*"))
							{
								Double m=stack.peek();
								stack.pop();
								Double n=Double.parseDouble(comput[i+1]);//把*前后两个数相乘再压栈
								stack.push(m*n);
							}
							if (comput[i].equals("/"))
							{
								Double m=stack.peek();
								stack.pop();
								Double n=Double.parseDouble(comput[i+1]);
								stack.push(m/n);
							}
						}
					}
					double sum=0;
					while (!stack.isEmpty())
					{
						sum=sum+stack.peek();
						stack.pop();
					}
					String result=String.valueOf(sum);//转换成字符串型
					return result;
				}
			});
			panel1.add(button);
		}
		frame.add(panel2,BorderLayout.NORTH);//置于顶部
		frame.add(panel1,BorderLayout.CENTER);
	}
	public static void main (String[] args)
	{
		new calculator();
	}
}