计算器在我们的生活中常常会使用到,本次课程设计,通过界面以及其中的逻辑处理,完成了四则运算的处理。通过awt包或者swing包中的界面设计部分对界面设计的细节可以有更多的了解。利用面向对象的思想,将各个组件的事件响应分别用不同的类表达出来。面向对象的思想从很大程度上可以让程序的思路更加清晰,而且可重用性很高。对于具有相同事件响应的组件则可以调用相同的类来处理事件。除此之外,利用栈的知识来解决运算符优先的问题也让我们对java中的栈有了更多的了解。
二.课程设计的任务与要求
a. 使用Java的awt包或Swing包的类库设计图形界面的计算器
b 该计算器能够完成加减乘除的四则混合运算(注意运算优先级)
c 使用图形界面中的事件委托机制来处理事件响应
三.需求分析
1.该计算器完成的功能有:
用户能够完成四则混合运算+、-、*、/,并且计算器能够自动的识别运算符的优先级,根据输入的运算公式,自动计算出相应的结果。同时完成计算器中的backspace、ce按钮,能够完成消除或者删除的功能。
2.出错处理
当用户如果按下的是除零的操作,显示框将显示“被除数不能为0”。
当用户如果连续多次按下运算符,计算器自动记忆第一次运算符,并且做防连续输入相同的运算符或者是不同的运算符。
当用户在同一个数据中多次输入小数点,计算器能够自动判断小数点重复,自动只记忆第一个小数点。
当用户在同一个数据中输入多个负号,计算器能够自动做重复检查,不显示多余的负号。
当用户在使用backspace功能删除越界数据时候,计算器自动做相应处理。
3.数据处理
在程序的起始,建立了两个栈,分别用来存储操作数和操作符。在计算器的核心运算代买中,运用这两个栈来实现算法中的优先级的处理,使用“#”号来标记目标计算公式的结束。目标计算公式通过计算器的键盘实现输入,当按下“=”号之后,计算器通过调用计算器核心函数来实现数据的处理。
四.类层次中各个类的描述(包括属性和方法)
本次课程设计一共分为了5个类,每个类都各自完成不同的功能。
●class MyCalculator: 类MyCalculator是主类,含有main()函数, 通过new CalFrame()来运行程序。
●class CalFrame: 类CalFrame完成的功能是计算器界面的设计,并且将每个组件都添加事件响应。具体的事件响应操作将在其他的类中逐一实现。
●class HandleWin:点击关闭windows窗口的控制类。
●class HandleNum:字符串输入控制类。
●Class HandleEqual:等号出发事件的响应机制类。
属性包括:
0~9的数字键
JButton num1; JButton num2; JButton num3; JButton num4;
JButton num5; JButton num6; JButton num7; JButton num8;
JButton num9; JButton num0;
+ - * / 四个控制按钮
JButton plus;
JButton minus;
JButton mutiply;
JButton divide;
. +/- 两个按钮
JButton point;
JButton sign;
Backspace ce = 三个按钮
JButton bs;
JButton ce;
JButton equal;
将这些按钮按照一定的顺序添加到现实面板中。
Panel p1,p2,p3,p4;
//为了布局的方便,利用borderLayout,通过几个面板来添加
Stack //用来记录操作数的栈 Stack //用来记录操作符的栈,栈底压入“#”,取到了“#"代表已到栈底 boolean pointswitch = true;//小数点开关 boolean oprateswitch = false;//运算符开关 boolean siginswitch = true;// 正负号开关 方法: public void actionPerformed(ActionEvent e) 当按下了控制按钮,根据搜索控制开关来确定能否继续添加,各个相应的处理机制。 public double segmentation(String myString) 字符串优先级计算代码的核心函数。 public int compare(char ch1,char ch2) 1值为ch1大于ch2;-1为ch1小于ch2;0为ch1等于ch2 public double oprate(double a,char b,double ce) 通过参数b来判断加减乘除 五.计算器界面的设计 本程序的实现使用了swing和awt两个包,主题程序界面按键根据微软计算器的布置界面进行设置,采用比较人性化的常规按键排布。返回计算结果的“=”号键使用了两倍于普通按键面积的设计,使的击中的概率更加大。 整体界面是采用了BorderLayout布局,通过4个panel进行布局的详细划分,panel3用来存储位于panel4左下角的GridLayout(1,2,4,4)布局,panel1、panel2、panel3分别用来表示BorderLayout的上中下三个模块。 Panel1中添加了一个Label display,display用来作为显示器,实时的显示输入和计算的数据。其中display需要设置为右对齐和只读属性。 Panel2中添加数字输入键和基本操作符键,panel采用了GridLayout布局,将整个panel2平分为4*4个空间,其中,数字键采用了15磅字体和蓝色文字,操作符采用了15磅字体和红色文字,是的界面更加显眼和便于区分。 Panel4中首先划分为GridLayout(1,2,4,4),在Panel4中,再次使用了GridLayout(1,2,4,4)将panel4的左侧一分为二,左边为panle3,这个的基础上程序往panel3中添加了backspace和ce两个按键,在Panel4的右侧单元格中添加了“=”号按钮,这个时候的“=”号就是相当于两个普通按钮的长度和大小。 整个程序界面的设计工作基本完成。 六.系统测试截图 1.系统初始运行界面 图1 系统初始运行界面截图 2.计算器按键测试 图2 系统按键测试截图 3.运算符重复输入测试 图3 加号重复输入测试截图 3.被除数为0的测试 图4 1/0的结果Infinity截图 4.小数点重复性检查 图5 小数点重复输入错误检查截图 5.backspace按键越界操作 图6 使用backspace键做越界操作的截图 6.优先级程序计算 图7 计算2/3+6*9-3截图 7.计算结果 图8 上面有优先级的公式计算结果 七.设计步骤 本次最先开始程序界面的设计,通过界面的设计,这样心中更加清楚功能的完成。所以先实现了一个类CalFrame,将每一个需要的组件全都进行添加进来,并运用了相应的布局方式。这样一个界面就显示出来了。其实在这个过程中还进行了很多次布局方式的尝试,但最后也是以上面所说的这种来完成。因为一共才学习了四种布局方式,应用能力有局限。 接下来逐步实现逻辑功能。即每个组件的事件响应。因为后面还涉及到运算符的优先级的问题,需要应用到栈,所以先完成一些简单的操作。 接下来完成的是数字键的事件响应。这样后面的其他按钮的事件响应才能继续下去。因此完成基本的数据显示是必须得。这个实现是很简单的,通过actionPerformed的实现,获取到了信息来实现相应功能的输出。 在actionPerformed中需要完成的还有ce 以及backspace 按钮的事件响应。首先弄清楚了虽然两个键代表的是清空和清除。backspace按钮的事件响应。完成逐一删除单个数字的功能,利用到字符串中的取出相应长度的子字符串来完成显示框的显示。Ce则是将所以相关的控制开关和栈重置。 在完成了基本的这些操作后,将要进行的是运算符的运算过程。考虑到优先级的问题,将应用栈来完成。因此先定义了两个静态的栈来存入用户每次在按下等号之前输入的字符串的使用正则表达式的分解操作数和操作符。对于每个运算符的处理都是一样的,即将每次按下运算符时将显示框中的内容压入栈中,并且将该运算符压入栈中。 最后是对等于号的事件响应。通过慢慢的添加,计算器的运算功能就完成了。 八.总结 这个学期的java课程设计--计算器对我来说是一个不断学习,逐步完善的过程。开始的时候拿到题目看到只有四则混合运算就理所当然的认为应该是非常简单的的一个程序而已。 首先开始了程序的界面的设计。并且将一些简单的按钮的事件响应完成了。剩下了运算符优先级的问题以及数据的处理问题。于是在同学的帮助下利用正则表达式来完成输入字符串的切割,但是如果自己一个人单挑来说,对于题目中的数据处理的问题一时不知道该如何与正则表达式连接上。最后我还是选择用栈来处理。这个过程让我明白了学习知识的时候实践与理论之间是有很大的差异的。应用能力我还有待加强。于是我开始熟悉栈的使用。以前在c++的学习中接触过栈,这次的使用思想是一样的,只需要在了解一下java 中的相关一些函数便可。但实际在写程序的过程中,由于有一些特殊情况的考虑与进出入栈的联系,还是碰到了一些问题。但在后来我慢慢的整理清楚思路以后,逻辑列清楚了,便也将这些问题解决了。逐步的将各项功能都完善了。当然目前我的计算器也只是完成了四则混合运算,实际上还应该有很多功能可以添加入计算器的。 本次java课程设计也让我明白只要我一步步去做,那么程序功能便会不断强大。同时很重要的一点便是以后要多加强自己的动手实践能力。 参考文献 [1] 设计与开发大全/邱哲,王俊标,马斗编著.北京:清华大学出版社,2006.2 [2] 应用开发详解/刘晓华,张建,周慧贞编著.—3版.—北京:电子工业出版社,2007.1 附录A:程序源代码 import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MyCalculator { public static void main(String[] args){ new CalFrame(); } } class CalFrame extends JFrame { String opnt,optr; Stack Stack Label display; //显示 JButton []num = new JButton[10];//按键设计 JButton plus; JButton minus; JButton mutiply; JButton divide; JButton bs;JButton ce;JButton equal; JButton point; JButton sign;JButton lbracket; JButton rbracket; Panel p1,p2,p3,p4; String disp = "";//用户输入的表达式 String result = "" ;//用户输入的字符串 CalFrame(){ OPTR.push("#"); for(int i=0;i<=9;++i){ num[i] = new JButton(String.valueOf(i)); } plus = new JButton("+"); plus.setForeground(Color.red); plus.setFont(new Font("Dialog",1,15)); minus = new JButton("-"); minus.setForeground(Color.red); minus.setFont(new Font("Dialog",1,15)); mutiply = new JButton("*"); mutiply.setForeground(Color.red); mutiply.setFont(new Font("Dialog",1,15)); divide = new JButton("/"); divide.setForeground(Color.red); divide.setFont(new Font("Dialog",1,15)); equal = new JButton("="); equal.setForeground(Color.red); equal.setFont(new Font("Dialog",1,15)); point = new JButton("."); point.setFont(new Font("Dialog",1,15)); sign = new JButton("+/-"); sign.setFont(new Font("Dialog",1,15)); bs = new JButton("backspace"); bs.setForeground(Color.red); bs.setFont(new Font("Dialog",1,8)); ce = new JButton("ce"); ce.setFont(new Font("Dialog",1,15)); p1 = new Panel(); p1.setLayout(new BorderLayout()); display = new Label("0.",Label.RIGHT); display.setBackground(Color.white); p1.add(display,BorderLayout.NORTH); p2 = new Panel(); p2.setLayout(new GridLayout(4,4,4,4)); p2.add(num[7]);p2.add(num[8]);p2.add(num[9]);p2.add(divide); p2.add(num[4]);p2.add(num[5]);p2.add(num[6]);p2.add(mutiply); p2.add(num[1]);p2.add(num[2]);p2.add(num[3]);p2.add(minus); p2.add(num[0]);p2.add(sign);p2.add(point);p2.add(plus); p3 = new Panel(new GridLayout(1,2,4,4)); p3.add(bs);p3.add(ce); p4 = new Panel(new GridLayout(1,2,4,4)); p4.add(p3); p4.add(equal); setTitle("超级计算器"); setLayout(new BorderLayout()); add(p1,BorderLayout.NORTH); add(p2,BorderLayout.CENTER); add(p4,BorderLayout.SOUTH); setVisible(true); pack(); setResizable(false); setBounds(600,350,300,230); addWindowListener(new HandleWin()); for(int i=0;i<=9;++i){ num[i].setForeground(Color.blue); num[i].setFont(new Font("Dialog",1,15)); num[i].addActionListener(new HandleNum(this,i)); } plus.addActionListener(new HandleNum(this)); minus.addActionListener(new HandleNum(this)); mutiply.addActionListener(new HandleNum(this)); divide.addActionListener(new HandleNum(this)); point.addActionListener(new HandleNum(this)); sign.addActionListener(new HandleNum(this)); bs.addActionListener(new HandleNum(this)); ce.addActionListener(new HandleNum(this)); equal.addActionListener (new HandleEqual(this)); } class HandleWin extends WindowAdapter{//关闭计算器 public void windowClosing(WindowEvent e){ (e.getWindow()).dispose(); System.exit(0); } } boolean pointswitch = true;//小数点开关 boolean oprateswitch = false;//运算符开关 boolean siginswitch = true;// class HandleNum implements ActionListener{//字符串的输入 JFrame my_Num; int itemp = 0; HandleNum(JFrame f,int a){ my_Num = f; itemp = a; } HandleNum(JFrame f){ my_Num = f; } public void actionPerformed(ActionEvent e){ if(e.getSource()==num[itemp]){//输入数字字符 oprateswitch = true; siginswitch = false; disp = disp + itemp; display.setText(disp); } if(oprateswitch&&e.getSource()==plus){//输入加号 pointswitch = true; oprateswitch = false; siginswitch = true; disp = disp + "+"; display.setText(disp); } if(oprateswitch&&e.getSource()==minus){//输入减号 pointswitch = true; oprateswitch = false; siginswitch = true; disp = disp + "-"; display.setText(disp); } if(oprateswitch&&e.getSource()==mutiply){//输入乘号 pointswitch = true; oprateswitch = false; siginswitch = true; disp = disp + "*"; display.setText(disp); } if(oprateswitch&&e.getSource()==divide){//输入除号 pointswitch = true; oprateswitch = false; siginswitch = true; disp = disp + "/"; display.setText(disp); } if(oprateswitch&&pointswitch==true&&e.getSource()==point){//输入小数点 pointswitch = false; oprateswitch = false; siginswitch = false; disp = disp + "."; display.setText(disp); } if(siginswitch&&e.getSource()==sign){//输入负号 disp = disp + "—"; display.setText(disp); } if(e.getSource()==bs){//点击backspace if(!disp.isEmpty()){ disp = disp.substring(0,disp.length()-1); if(disp.isEmpty()) disp=" "; display.setText(disp); } } if(e.getSource()==ce){//点击ce disp = " "; display.setText(disp); } } } class HandleEqual implements ActionListener{// 等于号触发的事件 Frame my_Equal; HandleEqual(JFrame f){ my_Equal = f; } public void actionPerformed(ActionEvent e){ if(e.getSource()==equal){ disp = disp+"#"; disp = String.valueOf(segmentation(disp)); display.setText(disp); disp = ""; pointswitch = true;//小数点开关 oprateswitch = false;//运算符开关 siginswitch = true; //符号开关 } } public double segmentation(String myString){ String reg = "(\\\\—?\\\\d+\\\\.?\\\\d*)|([-+*/()#])"; //分割表达式. Pattern p = Pattern.compile(reg); Matcher m = p.matcher(myString); String find = ""; double num = 0; double op1,op2; char op3; while(m.find()){ find = m.group(); find = find.replace('—','-'); try{ num = Double.valueOf(find); OPNT.push(num); }catch(NumberFormatException nfe){ //find为操作符 if(compare(((OPTR.peek()).charAt(0)),find.charAt(0))==-1){ OPTR.push(find); } else { while(compare(((OPTR.peek()).charAt(0)),find.charAt(0))==1){ op2=OPNT.pop(); op1=OPNT.pop(); op3=(OPTR.pop()).charAt(0); OPNT.push(oprate(op1,op3,op2)); } if(compare(((OPTR.peek()).charAt(0)),find.charAt(0))==0){ OPTR.pop(); continue; } OPTR.push(find); if(compare(((OPTR.peek()).charAt(0)),find.charAt(0))==2){ if(OPNT.isEmpty()){ while(!OPNT.isEmpty()){ OPTR.pop(); } OPTR.push("#"); return 0; } return OPNT.pop(); } if(compare(((OPTR.peek()).charAt(0)),find.charAt(0))==3) return 0; } } } return 0.0; } public int compare(char ch1,char ch2){//1值为ch1大于ch2;-1为ch1小于ch2;0为ch1等于ch2 switch(ch1){ case '+':if(ch2=='+'||ch2=='-'||ch2=='#') return 1; else return -1; case '-':if(ch2=='+'||ch2=='-'||ch2=='#') return 1; else return -1; case '*':return 1; case '/':if(ch2=='(') return -1; else return 1; case '#':if(ch2=='#') return 2; else return -1; default :return 3; } } public double oprate(double a,char b,double ce){ if(b=='+') return a+ce; else if(b=='-') return a-ce; else if(b=='*') return a*ce; else return a/ce; } } }