作业五: 结对项目-四则运算 "软件"之升级版
作业要求来自https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2232
提交作业的github远程仓库的地址:https://github.com/codeforsome/proTwo
结对同伴的学号姓名:黄曼金
结对同伴的博客地址 :http://www.cnblogs.com/manjin666
-
开发及调试环境:Eclipse
___________________________________________________________________________________________
二、四个扩展要求:
___________________________________________________________________________________________
-
程序可以出带括号的正整数四则运算,支持分数,除法保留两位小数,如:(1/3+1)*2 = 2.67,特别注意:这里是2.67而非2.66,或保持分数形式:8/3
-
可以出表达式里含有负整数(负整数最小不小于-100)的题目,且负数需要带括号,用户输入的结果不用带括号。如: 2*(-4) = -8
-
用户可以选择出题的个数(最多不能超过5个题目),答题结束可以显示用户答错的题目个数和答对的题目个数
-
程序可以设置皮肤功能,可以改变界面的颜色即可
三、源代码
___________________________________________________________________________________________
工具:Eclipse
语言:Java

1 package test; 2 3 import java.io.IOException; 4 import java.util.*; 5 //产生题目和答案的一个类 6 public class Exercises { 7 public static void main(String[] args) { 8 } 9 private int minNumber=-100; //题目出现的最小数字 10 private int maxNumber=100; //题目出现的最大数字 11 private int count=2; //题目初始化的题目数量 12 private String result=""; //题目的字符串量 13 private float resultNumber=0; //题目的正确答案 14 //用来保存每一道题目和题目答案 15 private Map<Integer, Result> exercisesMap=new HashMap<Integer, Result>(); 16 //用来保存要用到的运算符号 17 private char operations[]=new char[]{'+','-','*','/'}; 18 // 该类用来保存结果的答案 19 public class Result{ 20 public String result; 21 public float resultNumber; 22 } 23 //获得题目数量 24 public int getCount() { 25 return count; 26 } 27 28 public Map<Integer, Result> getExercisesMap() { 29 return exercisesMap; 30 } 31 32 public void setCount(int count) { 33 this.count = count; 34 } 35 // 获得随机数 36 private int getRandomNumber(){ 37 return (int)(minNumber+Math.random()*(maxNumber-minNumber+1)); 38 } 39 private char getRandomOperation(){//获得随机运算符号 40 int random=(int)(Math.random()*operations.length); 41 return operations[random]; 42 } 43 // 计算四则结果 44 private float getOperationResult(char operation,float x,float y){ 45 float result=0; 46 switch (operation){ 47 case '+': 48 result=x+y; 49 break; 50 case '-': 51 result=x-y; 52 break; 53 case '*': 54 result=x*y; 55 break; 56 case '/': 57 result=x/y; 58 break; 59 } 60 return result; 61 } 62 public void arithmetic(){//每次产生一道题目 63 int number[]=new int[3]; //运算数量 64 char []operation=new char[2]; //符号数量 65 while (true){ 66 for(int i=0;i<number.length;i++){ 67 number[i]=getRandomNumber(); //给变量赋值 68 } 69 operation[0]=getRandomOperation(); //给符号位赋值 70 operation[1]=getRandomOperation(); 71 if(operation[0]=='*' || operation[0]=='/'){ //判断第一个是否为*,/ 是,则直接计算 72 if(number[1]==0)continue; 73 resultNumber=getOperationResult(operation[0],number[0],number[1]); 74 if(operation[1]=='/' && number[2]==0)continue; 75 resultNumber=getOperationResult(operation[1],resultNumber,number[2]); 76 }else { 77 //如果第一个符号位不是* ,/那就先算第二个数和三个数的值后,再与第一个值计算 78 if(operation[1]=='/'&& number[2]==0)continue; 79 if(operation[0]=='-'){ 80 resultNumber=getOperationResult(operation[1],-number[1],number[2]); 81 operation[0]='+'; 82 } 83 else{ 84 resultNumber=getOperationResult(operation[1],number[1],number[2]); 85 operation[0]='-'; 86 } 87 resultNumber=getOperationResult(operation[0],number[0],resultNumber); 88 } 89 break; 90 } 91 // 将数字和符号串联起来 作为输出题目的字符 92 result=parseNumber(number[0])+operation[0]+parseNumber(number[1]) 93 +operation[1]+parseNumber(number[2])+"="; 94 // resultNumber= 95 } 96 // 转化负数带有中括号 97 private String parseNumber(int number){ 98 return number<0 ? "("+number+")" : number+""; 99 } 100 public Map<Integer, Result> showArithmetic(){//产生题目,答案并保存和输出 101 int countExercise=0; 102 while (countExercise<count){ 103 arithmetic(); 104 Result result=new Result(); 105 result.result=this.result; 106 result.resultNumber=this.resultNumber; 107 exercisesMap.put(countExercise,result); 108 countExercise++; 109 } 110 return exercisesMap; 111 } 112 113 }

1 package test; 2 3 import javax.swing.*; 4 5 import java.awt.*; 6 import java.awt.event.*; 7 import java.util.ArrayList; 8 import java.util.HashMap; 9 import java.util.List; 10 import java.util.Map; 11 import java.util.regex.Pattern; 12 13 public class ExercisesSwing implements ActionListener { 14 private JLabel jlabelExercise,jlabelTip; 15 private JFrame jfrm; 16 private JTextField jtfInput; 17 // 第一个题目的初始位置和距离 18 private int startX=20,startY=20,distance=220; 19 private Map<Integer,Exercises.Result> map; //保存所有的题目 20 private Map<Integer,JTextField> mapJtfInput; //保存用户输入框 21 private Exercises exercises; //题目类 22 private static class Score{ //保存答错题数和答题总数 23 public static int errorCount=0; 24 public static int num=0; 25 } 26 private JMenuBar menubar; //菜单条 27 private JMenu menuSet,menuColor; //菜单 28 private JMenuItem itemColorCYAN, itemColorYELLOW,itemColorPICK; //颜色菜单项 29 private JMenuItem itemCount; 30 private JPanel jPanel; 31 32 public static class Constant{//程序用到的数据常量 33 // 以下三个常量是试题所在的宽度和高度以及字体大小 34 private static final int JLABEl_WIDTH=220; 35 private static final int HEIGHT=25; 36 private static final int JLABEl_FONTSIZE=20; 37 private static final int JTF_INPUT_WIDTH=100; 38 private static final int STRATY=20; 39 // 菜单栏中可以选择的题目最大数字 40 private static final int EXERCICESCOUNT=5; 41 } 42 ExercisesSwing(){ 43 init(); //程序的加载和初始化 44 } 45 private void init(){ 46 exercises=new Exercises(); 47 jfrm=new JFrame("四则运算"); 48 jPanel=new JPanel(); 49 jPanel.setBounds(0,0,600,6000); 50 jPanel.setBackground(Color.CYAN); 51 jPanel.setLayout(null); 52 jfrm.setLayout(null); 53 jfrm.setSize(600,600); 54 jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 55 jfrm.setLocation(100,100); 56 initMenu(); 57 jlabelTip=new JLabel(); 58 jPanel.add(jlabelTip); 59 jPanel.setVisible(true); 60 showExercises(); 61 jfrm.add(jPanel); 62 jfrm.setVisible(true); 63 } 64 private void showExercises(){ 65 map=exercises.showArithmetic(); 66 mapJtfInput=new HashMap<Integer, JTextField>(); 67 Score.errorCount=0; 68 Score.num=0; 69 startY=20; 70 for (int i=0;i<exercises.getCount();i++){ 71 startY+=Constant.HEIGHT; 72 jlabelExercise=new JLabel(map.get(i).result); 73 jlabelExercise.setFont(new Font("宋体",Font.BOLD, Constant.JLABEl_FONTSIZE )); 74 jlabelExercise.setBounds(startX,startY,Constant.JLABEl_WIDTH,Constant.HEIGHT); 75 jtfInput=new JTextField(10); 76 jtfInput.addKeyListener(new KeyAdapter() { 77 @Override 78 public void keyTyped(KeyEvent e) { 79 int key = e.getKeyChar(); 80 // 只能输入数字 81 char keyCh = e.getKeyChar(); 82 if ((keyCh < '0') || (keyCh > '9')) { 83 if(keyCh=='-'||keyCh=='.'){ 84 85 } 86 else if(keyCh != KeyEvent.VK_ENTER ){ 87 e.setKeyChar(''); 88 } 89 } 90 91 if (key == KeyEvent.VK_ENTER) { 92 String sub="JTextField[,"+(distance+startX)+","; 93 int indexOf=e.toString().indexOf(sub)+sub.length(); 94 int lastOf=e.toString().indexOf(Constant.JTF_INPUT_WIDTH+"x"+Constant.HEIGHT); 95 String inputNumber = e.toString(); 96 if(lastOf<indexOf) 97 return; 98 String targetY=e.toString().substring(indexOf,lastOf-1); 99 int count= (Integer.parseInt(targetY)-Constant.STRATY ) /Constant.HEIGHT-1; 100 mapJtfInput.get(count).setEditable(false); 101 } 102 } 103 }); 104 mapJtfInput.put(i,jtfInput); 105 jtfInput.setBounds(startX+distance,startY,Constant.JTF_INPUT_WIDTH,Constant.HEIGHT); 106 jtfInput.addActionListener(this); 107 jPanel.add(jlabelExercise); 108 jPanel.add(jtfInput); 109 110 } 111 112 } 113 // 初始化菜单内容 114 private void initMenu(){ 115 menubar = new JMenuBar(); 116 menuSet = new JMenu("选择题目数量"); 117 for(int i=0;i<Constant.EXERCICESCOUNT;i++){ 118 itemCount=new JMenuItem((i+1)+""); 119 itemCount.addActionListener(this); 120 menuSet.add(itemCount); 121 } 122 menuColor = new JMenu("颜色设置"); 123 itemColorCYAN=new JMenuItem("深加蓝"); 124 itemColorYELLOW=new JMenuItem("天然黄"); 125 itemColorPICK=new JMenuItem("少女粉"); 126 menuColor.add(itemColorCYAN); 127 menuColor.add(itemColorYELLOW); 128 menuColor.add(itemColorPICK); 129 menubar.add(menuSet); //将菜单添加到菜单条上 130 menubar.add(menuColor); 131 jfrm.setJMenuBar(menubar); 132 setMenuItemEvent(); 133 } 134 // 设置菜单颜色按钮事件 135 private void setMenuItemEvent(){ 136 itemColorCYAN.addMouseListener(new MouseAdapter() { 137 @Override 138 public void mousePressed(MouseEvent e) {//只能检测到mousePressed事件 139 super.mouseClicked(e); 140 jPanel.setBackground(Color.CYAN); 141 } 142 }); 143 itemColorYELLOW.addMouseListener(new MouseAdapter() { 144 @Override 145 public void mousePressed(MouseEvent e) {//只能检测到mousePressed事件 146 super.mouseClicked(e); 147 jPanel.setBackground(Color.YELLOW); 148 } 149 }); 150 itemColorPICK.addMouseListener(new MouseAdapter() { 151 @Override 152 public void mousePressed(MouseEvent e) {//只能检测到mousePressed事件 153 super.mouseClicked(e); 154 jPanel.setBackground(Color.pink); 155 156 } 157 }); 158 } 159 public void repaintJPanel(int number){ 160 jPanel.removeAll(); 161 jPanel.repaint(); 162 exercises.setCount(number); 163 showExercises(); 164 return; 165 } 166 public static boolean isInteger(String str) { 167 Pattern pattern = Pattern.compile("^[-\+]?[\d]*$"); 168 return pattern.matcher(str).matches(); 169 } 170 // 对所有组件进行监听事件 171 public void actionPerformed(ActionEvent e) { 172 // 获取组件值 173 String targetNumber=e.getActionCommand(); 174 // 如果用户按下的组件是菜单的选择数字 则对页面进行重绘 175 if(!targetNumber.equals("")|| !isInteger(targetNumber)){ 176 177 int number=Double.valueOf(targetNumber).intValue(); 178 // Integer.parseInt(targetNumber); 179 if( number>0 && number<=Constant.EXERCICESCOUNT) 180 repaintJPanel(number); //重绘页面上的试题 即对试题进行刷新 181 } 182 // 以下是对用户输入答案后 对用户答案进行判断 和输出文字 183 184 // 首先获取用户输入框的位置 然后再输入框的位置右边输出要显示的信息 185 String sub="JTextField[,"+(distance+startX)+","; 186 int indexOf=e.toString().indexOf(sub)+sub.length(); 187 int lastOf=e.toString().indexOf(Constant.JTF_INPUT_WIDTH+"x"+Constant.HEIGHT); 188 String inputNumber = e.getActionCommand(); 189 if(lastOf<indexOf) 190 return; 191 String targetY=e.toString().substring(indexOf,lastOf-1); 192 int count= (Integer.parseInt(targetY)-Constant.STRATY ) /Constant.HEIGHT-1; 193 jlabelTip=new JLabel(); 194 if(inputNumber.equals("")) 195 inputNumber="-1"; 196 float result=map.get(count).resultNumber-Float.parseFloat(inputNumber); 197 if(Math.abs(result)<0.01){ 198 jlabelTip.setText("你答对了"); 199 }else{ 200 jlabelTip.setText("答错了,正确答案:"+ 201 String.format("%.2f", map.get(count).resultNumber)); 202 Score.errorCount++; 203 } 204 jPanel.add(jlabelTip); 205 jlabelTip.setBounds(startX+(int)(distance*1.5),Integer.parseInt(targetY),Constant.JTF_INPUT_WIDTH*2,Constant.HEIGHT); 206 // 以下是判断用户答错的题目和总的答题数目 在用户答题后 输入框便不能使用了 207 Score.num++; 208 if(Score.num==exercises.getCount()){ 209 jlabelTip=new JLabel(); 210 jPanel.add(jlabelTip); 211 jlabelTip.setText("你答对了"+(Score.num-Score.errorCount)+"道题 " 212 +"答错了"+Score.errorCount+"道题"); 213 jlabelTip.setBounds(100,Integer.parseInt(targetY)*2,Constant.JTF_INPUT_WIDTH*2,Constant.HEIGHT); 214 } 215 } 216 217 public static void main(String[] args) { 218 ExercisesSwing exercisesSwing=new ExercisesSwing(); 219 } 220 }
四、结对软件过程耗时估计与统计表
___________________________________________________________________________________________
PSP2.1 |
Personal Software Process Stages |
Time Senior Student |
Time (minute) |
Planning |
计划 |
8 |
9 |
· Estimate |
估计这个任务需要多少时间 |
12 |
25 |
Development |
开发 |
90 |
50 |
· Analysis |
需求分析 (包括学习新技术) |
20 |
30 |
· Design Spec |
生成设计文档 |
0 |
0 |
· Design Review |
设计复审 |
3 |
15 |
· Coding Standard |
代码规范 |
0 |
10 |
· Design |
具体设计 |
10 |
25 |
· Coding |
具体编码 |
35 |
30 |
· Code Review |
代码复审 |
10 |
25 |
· Test |
测试(自我测试,修改代码,提交修改) |
15 |
15 |
Reporting |
报告 |
9 |
9 |
· |
测试报告 |
0 |
0 |
· |
计算工作量 |
5 |
5 |
· |
并提出过程改进计划 |
0 |
0 |
五、项目的分工与工作照片:
_________________________________________________________________________________________
黄曼金同学负责代码的主要测试和编写,代码功能的构思和编写,程序的总体布局,
而我负责复审代码及优化代码。例如:选择题目数量时,不能在点击题目数量的时候立即更改到相应数量的题目数,经检查调试,我加入了repaint()方法的使用,就可以做到,立马改题目数量,立马显示的效果。同伴在修改背景颜色时,有遇到一些小问题,例如再改颜色时,有些颜色无法更改,更改完没显示之类的问题。经检查发现是改颜色的地方出错,不应该改到主面板,要改到副面板,副面板是覆盖到主面板上面的,当副面板有颜色时,对主面板修改背景颜色,是无法看见其修改的。
六、项目运行截图
___________________________________________________________________________________________
1:题目的选择
2:背景颜色的选择:
3:题目的提示和输入:
七、项目感想
___________________________________________________________________________________________
在结对项目中,两个人做一件事情,速度会快很多,当一个人卡住,想不到解决办法的时候,或许另一个人就会有好的解决办法,有时候,一个人想出的编写思路,说出来之后另一个人又有可能给出更好的编写思路,两个人不断进步,程序不断优化。需要注意的是,写代码时一定要注意代码的规范,写好注释,不然有时候回看代码的时候,效率会降低。