201571030112/201571030108 《小学四则运算练习软件》结对项目报告;
一、github链接地址
https://github.com/Transform21/treasury/tree/master/Update_End
二、结对项目报告
a. 需求分析:
在《实验二 软件工程个人项目》中,我们已经实现了一个命令行四则运算出题小程序,为了更好的达到训练效果,我们设计开发了一个小学生四则运算练习软件,需求分析内容如下:
(1)、针对小学生这一用户群体,专项测试能帮助他们检验学习效果,同时多次训练也有助于更好的掌握所学内容。于是我们设计由计算机从题库文件中随机选择20道加减乘除混合算式,用户输入算式答案,程序检查答案是否正确,每道题正确计分,错误不计分,20道题测试结束后给出测试总分,用这样的方式让学生知道自己的能力水平程度。
(2)、小学生运算难度是确定并有限制的,因而设立专门针对于小学生的题库。由计算机从题库文件中随机选择20道加减乘除混合算式,用户输入算式答案,程序检查答案是否正确,每道题正确计5分,错误不计分,20道题测试结束后给出测试总分,整数题库示例如下图所示:
(3)、量变引起质变。对于小学生来说,四则运算的掌握无外乎要多多做练习,因而程序允许用户进行多轮测试,在更好的达到训练目的的同时,为用户提供多轮测试分数柱状图,让用户直观的感受学习效果,示例如下:
(4)、小学生计算能力的提升不光要看他的正确率,还要看他做计算题时的用时和速度,综合结果才是小学生能力水平体现。,因而测试设立计时功能,每一轮测试完成都会返回用户所用答题时间。
(5)、为了让用户有更好的体验,程序设计人机交互界面是GUI界面,让用户更具界面内容提示完成测试。
(6)、小学生的知识结构是一点一点建立起来的,学习也有循序渐进的过程,于是程序设计为用户提供三种进阶四则运算练习功能选择:百以内整数算式、带括号算式以及真分数算式练习;
b.程序流程图
c. 软件设计:
本项目共有五个类
(1)Main( )类:用户窗口的登录界面;
(2)Start( )类:产生答题窗口,并设立界面各个按钮监听事件,
(3)Calculate_SE()类:运算式产生,产生整数运算式、分数运算式文件。
(4)Timer()类:产生计时窗口。
(5)Chart_H( )类:绘制成绩柱状图。
d. 核心功能代码展示:展示核心功能代码。
- 关于整数和分数题的获取和显示:
关于整数和分数选题部分,我们在界面当中设置两个可选按钮,当选中相应按钮时,用户界面显示对应的计算式。
以整数部分为例,当按下按键时设置事件监听,获取Calculate_SE类当中产生的计算式,为了界面设置的简洁,我们用CA.IntegerQ.get(number)这一语句获取每一条计算式,计算式都放入一个label当中,
1 //---------------------------------------整数------------------------- 2 3 JRadioButton buttonInteger=new JRadioButton("整数");//JRadioButton 4 buttonInteger.addItemListener(new ItemListener() { 5 public void itemStateChanged(ItemEvent arg0) { 6 frame2.pack(); 7 frame2.setVisible(true); 8 try { 9 CA.calaulate_AE(40); 10 } catch (IOException e) { 11 e.printStackTrace(); 12 } 13 String shizi = CA.IntegerQ.get(number); 14 NUM++; 15 label1.setText(shizi); 16 } 17 }); 18 //--------------------------------分数--------------------------------- 19 JRadioButton buttonFenshu = new JRadioButton("分数"); 20 buttonFenshu.addItemListener(new ItemListener() { 21 public void itemStateChanged(ItemEvent arg0) { 22 frame2.pack(); 23 frame2.setVisible(true); 24 try { 25 CA.fenshu(); 26 } catch (IOException e) { 27 e.printStackTrace(); 28 } 29 String shizi = CA.FractionQ.get(number); 30 NUM++; 31 label1.setText(shizi); 32 } 33 });
- 关于提交答案后的错题分析展示
点击提交答案的按钮过后,所提供给用户的功能时,(1)让用户看到自己的答题用时;(2)显示用户的做题状态,并给出正确答案,最后统计用户得分。
关于答题用时,我们将计时类当中最终统计的时间每一次都存入文件当中,在最终提交答案时,读取文件中的内容返回给timeLabel中;关于做题状态,将text中用户所所填写的答案与Arraylist当中已存取的答案进行比较,若相同则状态为正确,若不同,则状态值错误。
JButton buttonSubmit=new JButton("提交答案"); buttonSubmit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { frame2.dispose(); if(buttonInteger.isSelected()) { String question=label1.getText(); String result=text.getText(); String ifRight=""; String time; if((CA.IntegerA.get(number)).equals(result)){ ifRight="正确"; rightSum++; }else{ ifRight="错误"; } String message=question+", "+"你的答案:"+result+", "+"正确答案: "+CA.IntegerA.get(number)+", 状态: "+ifRight; list.add(message); text.setText(""); } if(buttonFenshu.isSelected()) { String question=label1.getText(); String result=text.getText(); String ifRight=""; if(CA.FractionA.get(number).equals(result)){ ifRight="正确"; rightSum++; }else{ ifRight="错误"; } String message=question+", "+"你的答案:"+result+", "+"正确答案: "+CA.FractionA.get(number)+", 状态: "+ifRight; list.add(message); text.setText(""); } //----------------------------------------- // temp=number-1; String score=String.valueOf(rightSum*5); newList.add(score); File file = new File("test.txt"); BufferedWriter bw = null; try { bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("test.txt", true))); bw.newLine(); bw.write(score); } catch (Exception e1) { e1.printStackTrace(); } finally { try { bw.close(); } catch (IOException e1) { e1.printStackTrace(); } } File file1 = new File("time.txt"); FileReader fr1 = null; BufferedReader br1 = null; String time=""; try { fr1 = new FileReader(file1); br1 = new BufferedReader(fr1); String line = ""; while((line = br1.readLine()) != null) { time=line; } } catch (Exception e1) { e1.printStackTrace(); } finally { try { br1.close(); fr1.close(); } catch (Exception e1) { e1.printStackTrace(); } } int size=list.size(); int errorSum=size-rightSum; JFrame resultFrame=new JFrame(); resultFrame.setTitle("运算结果"); resultFrame.setSize(500,500); resultFrame.setLocationRelativeTo(null); resultFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); resultFrame.setVisible(true); JPanel panel7 = new JPanel(); Timelabel.setText("您本轮答题用时为:"+time); panel7.add(Timelabel); resultFrame.add(panel7,BorderLayout.NORTH); setLayout(new GridLayout(10,2,5,5)); JPanel panel=new JPanel(); Font font = new Font(Font.DIALOG, Font.PLAIN, 20); panel.add(new JLabel("做题总数: "+size+" "+"正确数:"+rightSum+" "+" 最终得分:"+rightSum*5)); setLayout(new GridLayout(100,2,5,5)); for(int i=0;i<size;i++){ panel.add(new JLabel(list.get(i))); } JPanel panel6=new JPanel(); panel6.add(buttonFenXi); panel6.add(buttonAgain); resultFrame.add(panel); resultFrame.add(panel6,BorderLayout.SOUTH); }});
- 关于计时部分的代码
- 此部分运用线程知识,用System.currentTimeMillis()等系统函数获取相应时间。
-
1 import javax.swing.*; 2 import java.awt.HeadlessException; 3 import java.awt.BorderLayout; 4 import java.awt.FlowLayout; 5 import java.awt.Font; 6 import java.awt.event.ActionListener; 7 import java.io.BufferedReader; 8 import java.io.BufferedWriter; 9 import java.io.File; 10 import java.io.FileReader; 11 import java.io.FileWriter; 12 import java.io.IOException; 13 import java.awt.event.ActionEvent; 14 15 /** 16 * 计时器 17 */ 18 public class Timer extends JFrame { 19 20 private static final long serialVersionUID = 1L; 21 private static final String INITIAL_LABEL_TEXT = "00:00:00 000"; 22 // 计数线程 23 private CountingThread thread = new CountingThread(); 24 // 记录程序开始时间 25 private long programStart = System.currentTimeMillis(); 26 // 程序一开始就是暂停的 27 private long pauseStart = programStart; 28 // 程序暂停的总时间 29 private long pauseCount = 0; 30 private JLabel label = new JLabel(INITIAL_LABEL_TEXT); 31 private JButton startPauseButton = new JButton("开始"); 32 private JButton resetButton = new JButton("清零"); 33 String time; 34 private ActionListener startPauseButtonListener = new ActionListener() { 35 public void actionPerformed(ActionEvent e) { 36 if (thread.stopped) { 37 pauseCount += (System.currentTimeMillis() - pauseStart); 38 thread.stopped = false; 39 startPauseButton.setText("暂停"); 40 } else { 41 pauseStart = System.currentTimeMillis(); 42 thread.stopped = true; 43 startPauseButton.setText("继续"); 44 } 45 } 46 }; 47 private ActionListener resetButtonListener = new ActionListener() { 48 public void actionPerformed(ActionEvent e) { 49 pauseStart = programStart; 50 pauseCount = 0; 51 thread.stopped = true; 52 label.setText(INITIAL_LABEL_TEXT); 53 startPauseButton.setText("开始"); 54 } 55 }; 56 public Timer(String title) throws HeadlessException { 57 super(title); 58 setDefaultCloseOperation(EXIT_ON_CLOSE); 59 setLocation(300, 300); 60 setResizable(false); 61 62 setupBorder(); 63 setupLabel(); 64 setupButtonsPanel(); 65 startPauseButton.addActionListener(startPauseButtonListener); 66 resetButton.addActionListener(resetButtonListener); 67 thread.start(); // 计数线程一直就运行着 68 } 69 // 为窗体面板添加边框 70 private void setupBorder() { 71 JPanel contentPane = new JPanel(new BorderLayout()); 72 contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 73 this.setContentPane(contentPane); 74 } 75 // 配置按钮 76 private void setupButtonsPanel() { 77 JPanel panel = new JPanel(new FlowLayout()); 78 panel.add(startPauseButton); 79 panel.add(resetButton); 80 add(panel, BorderLayout.SOUTH); 81 } 82 // 配置标签 83 private void setupLabel() { 84 label.setHorizontalAlignment(SwingConstants.CENTER); 85 label.setFont(new Font(label.getFont().getName(), label.getFont().getStyle(), 40)); 86 this.add(label, BorderLayout.CENTER); 87 } 88 89 private class CountingThread extends Thread { 90 91 public boolean stopped = true; 92 93 private CountingThread() { 94 setDaemon(true); 95 } 96 97 @Override 98 public void run() { 99 while (true) { 100 if (!stopped) { 101 long elapsed = System.currentTimeMillis() - programStart - pauseCount; 102 label.setText(format(elapsed)); 103 time=label.getText(); 104 File f=new File("time.txt"); 105 BufferedWriter bw; 106 try { 107 bw = new BufferedWriter(new FileWriter(f)); 108 bw.write(time); 109 bw.close(); 110 } catch (IOException e) { 111 // TODO Auto-generated catch block 112 e.printStackTrace(); 113 } 114 } 115 116 try { 117 sleep(1); // 1毫秒更新一次显示 118 } catch (InterruptedException e) { 119 e.printStackTrace(); 120 System.exit(1); 121 } 122 } 123 } 124 125 // 将毫秒数格式化 126 private String format(long elapsed) { 127 int hour, minute, second, milli; 128 129 milli = (int) (elapsed % 1000); 130 elapsed = elapsed / 1000; 131 132 second = (int) (elapsed % 60); 133 elapsed = elapsed / 60; 134 135 minute = (int) (elapsed % 60); 136 elapsed = elapsed / 60; 137 138 hour = (int) (elapsed % 60); 139 140 return String.format("%02d:%02d:%02d:%03d", hour, minute, second, milli); 141 } 142 } 143 }
e. 程序运行截图:
(1) 首先进入用户的登录窗口,用户需要输入姓名学号等信息。
(2)用户登录后,进入正式的答题界面,在这一界面当中,用户每进行一轮测试,在下一轮当中都会显示上一轮用户的成绩。
用户需要根据需求点击所需要训练的内容。
(3)在用户答题至第二十题时,答题结束,提示用户将答案提交。
(4)提交答案后我们可以看到生成的用户做题结果。
(5)优化后的题目分析状态图。
(6)根据用户多轮测试,将用户测试数据显示到柱状图当中。
f.编程时的结对照片。
g.此次结对作业的PSP。
PSP2.1 | 任务内容 | 计划完成的时间(min) | 实际完成需要的时间(min) |
---|---|---|---|
PLanning | 计划 | 60 | 80 |
Estimate | 估计这个任务需要多少时间,并规划大致工作步骤 | 30 | 40 |
Developmet | 开发 | 480 | 520 |
Analysis | 需求分析(包括学习新技术) | 30 | 40 |
Design Spec | 生成设计文档 | 10 | 15 |
Design Revie | 设计复审(和同事审核设计文档) | 20 | 30 |
Coding Standard | 代码规范 | 30 | 40 |
Design | 具体设计 | 45 | 60 |
Coding | 具体编码 | 240 | 300 |
Code Review | 代码复审 | 30 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 20 | 30 |
Reporting | 报告 | 30 | 40 |
Test Report | 测试报告 | 20 | 20 |
Size Measurement | 计算工作量 | 5 | 5 |
Postmortem & Process Improvement Plan | 事后总结,并提出过程改机计划 | 20 | 30 |
h. 请使用汉堡评价法给你的小伙伴一些点评。
关于我的小伙伴嘛,她是一个很认真的女孩,对于项目的每一部分她都十分仔细,总是迎难而上,遇到问题不是焦躁而是冷静沉着的解决每一次困难,她的动手能力很强,做事从不拖沓,在我们做项目的过程中当我遇到其他事情时我总会想着先将问题放一放,却不知编程是一个持续的过程,间断后第二次又要重新梳理思路,无形中浪费很多时间。她也是一个很有主见的女孩儿,当我们想法出现碰撞时,她总能按照自己的想法去尝试每一个可能,最终找到解决办法。整个项目分为五个模块,运算式是在第一次作业的基础上完成的,对比来说,小伙伴的第一次作业代码比我工整许多,有更强的可扩展性,所以在运算式产生部分我们选择了她的代码,在编写完界面之后调用产生运算式的算法,加入计时器和柱状图,完成了我们一开始的想法,总之,很开心的一次合作,期待下一次~
i. 结对编程真的能够带来1+1>2的效果吗?通过这次结对编程,请谈谈你的感受和体会。
对于这个不用说,答案一定是肯定的,在整个过程中我们大概用了接近三天的时间完成,两个人合作真的节省了不少时间,在一个问题不会的时候总有一个人可以和你一起商量,比起一个人效率高很多,毕竟一个人调代码调不出来是真的很绝望的,多一个人帮忙在给出想法的同时无形中提高了自己的能力,很喜欢这样的编程方式,两个人一起看代码改代码,相比起一个人编码时的枯燥,两个人合作完成一个任务时取得的成就感十分让人开心。对于我们这次的合作,我把它当做一个学习的机会,学习他人优点,看到自己的不足,让自己一步步成长。
对于JAVA:算起来JAVA真的有很长时间都没有碰过了,一开始真的让我很痛苦,但就像老师说的那样,忘记不应该当作理由,当把一件自己认为困难的事努力做到时,对我来说也许就是一个很大的进步吧,现在自己的写代码水平还很堪忧,也许别人花费一两个小时的任务我需要花费十个小时来完成,虽然最后都能完成,但是时间成本真的大很多,都是不好好学习造的孽呀o(╥﹏╥)o。这学期对我来说比较特殊,要复习考研,时间十分紧张,但却依然要抽工夫完成这些,现在看来最好的办法就是好好花功夫把JAVA再温习一遍了,还好之前有基础,过程也不是很困难,我想也只有这样自己才能节省更多时间去复习了。
关于学习画类图时用到的两个博客,记录下来留着下次用~
eclipse下生成Java类图和时序图,生成UML图
https://blog.csdn.net/u012714280/article/details/51678503
https://blog.csdn.net/wanmeirongyan100/article/details/51601570
一张无意看到的很有意思的插图~