任务1源码在Github的仓库主页链接地址:https://github.com/zhanghh2018/201571030135-201571030137
一、需求分析。
1)由计算机从题库文件中随机选择20道加减乘除混合算式,用户输入算式答案,程序检查答案是否正确,每道题正确计5分,错误不计分,20道题测试结束后给出测试总分;
2)题库文件可采用实验二的方式自动生成,也可以手工编辑生成。
3)程序为用户提供三种进阶四则运算练习功能选择:百以内整数算式(必做)、带括号算式、真分数算式练习;
4)程序允许用户进行多轮测试,提供用户多轮测试分数柱状图,示例如下:
5)程序记录用户答题结果,当程序退出再启动的时候,可为用户显示最后一次测试的结果,并询问用户可否进行新一轮的测试;
6)测试有计时功能,测试时动态显示用户开始答题后的消耗时间。
7)程序人机交互界面是GUI界面(WEB页面、APP页面都可),界面支持中文简体(必做)/中文繁体/英语,用户可以进行语种选择
二、软件设计:
1)流程图
2)类图(ContentToTxt():将内容写入文件 、ContinuTest():询问是否进行下一轮测试 、DTimeFrame():计时功能 、LoginIn():登录界面<登录账号:admin,密码:123456>、 PrintChart():绘制分数图、 ReadFile():一行一行读文件 、UI():答题界面)
三、核心功能代码展示:展示核心功能代码。
核心代码一:自动计时功能
import java.util.Date; import java.awt.Dimension; import java.text.SimpleDateFormat; import java.util.Calendar; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; /** * @author zhanghh * @time 2018.03.28 */ public class DTimeFrame extends JFrame implements Runnable{ private JFrame frame; private JPanel timePanel; private JLabel timeLabel; private JLabel displayArea; private String DEFAULT_TIME_FORMAT = "ss"; private int ONE_SECOND = 1000; public DTimeFrame(){ timePanel = new JPanel(); timeLabel = new JLabel("您当前用时: "); displayArea = new JLabel(); timePanel.add(timeLabel); timePanel.add(displayArea); this.add(timePanel); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setSize(new Dimension(200,100)); this.setBounds(900, 100, 200, 100); } public void run(){ int time=1; while(true){ SimpleDateFormat dateFormatter = new SimpleDateFormat(DEFAULT_TIME_FORMAT); displayArea.setText(time+"s"); try{ time++; Thread.sleep(ONE_SECOND); }catch(Exception e) { displayArea.setText("Error!!!"); } } } }
核心代码二:柱状图显示
import java.awt.Font; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartFrame; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.CategoryAxis3D; import org.jfree.chart.axis.NumberAxis3D; import org.jfree.chart.axis.NumberTickUnit; import org.jfree.chart.labels.ItemLabelAnchor; import org.jfree.chart.labels.ItemLabelPosition; import org.jfree.chart.labels.StandardCategoryItemLabelGenerator; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.category.BarRenderer3D; import org.jfree.data.category.DefaultCategoryDataset; import org.jfree.ui.TextAnchor; /** * * @author zhanghh * @time:2018.03.29 * @function:Display histogram * */ public class PrintChart { public static void print(int[] Score,int SubmissionsNum){ DefaultCategoryDataset dataset = new DefaultCategoryDataset(); //添加数据 for(int i=1;i<=SubmissionsNum;i++){ dataset.addValue(Score[i],"分数"+i, "第"+i+"轮"); } JFreeChart chart = ChartFactory.createBarChart3D("分数统计图", //主标题的名称 "测试次数", //X轴的标签 "测试分数(分数)", //Y轴的标签 dataset, //图标显示的数据集合 PlotOrientation.VERTICAL,//图像的显示形式(水平或者垂直) true, //是否显示子标题 true, //是否生成提示的标签 true);//是否生成url链接 //处理图形上的乱码 //处理主标题的乱码 chart.getTitle().setFont(new Font("宋体",Font.BOLD,18)); //处理子标题乱码 chart.getLegend().setItemFont(new Font("宋体",Font.BOLD,15)); //获取图表区域对象 CategoryPlot categoryPlot = (CategoryPlot) chart.getPlot(); //获取X轴的对象 CategoryAxis3D categoryAxis3D = (CategoryAxis3D) categoryPlot.getDomainAxis(); //获取Y轴的对象 NumberAxis3D numberAxis3D = (NumberAxis3D) categoryPlot.getRangeAxis(); //处理X轴上的乱码 categoryAxis3D.setTickLabelFont(new Font("宋体",Font.BOLD,15)); //处理X轴外的乱码 categoryAxis3D.setLabelFont(new Font("宋体",Font.BOLD,15)); //处理Y轴上的乱码 numberAxis3D.setTickLabelFont(new Font("宋体",Font.BOLD,15)); //处理Y轴外的乱码 numberAxis3D.setLabelFont(new Font("宋体",Font.BOLD,15)); //处理Y轴上显示的刻度,以1作为1格 numberAxis3D.setAutoTickUnitSelection(false); NumberTickUnit unit = new NumberTickUnit(100); numberAxis3D.setTickUnit(unit); //获取绘图区域对象 BarRenderer3D barRenderer3D = (BarRenderer3D) categoryPlot.getRenderer(); //设置柱形图的宽度 barRenderer3D.setMaximumBarWidth(0.07); //在图形上显示数字 barRenderer3D.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator()); barRenderer3D.setBaseItemLabelsVisible(true); //设置 barRenderer3D.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE1,TextAnchor.CENTER)); barRenderer3D.setBaseItemLabelFont(new Font("宋体",Font.BOLD,15)); //使用chartFrame对象显示图像 ChartFrame frame = new ChartFrame("测试分数统计", chart); frame.setVisible(true); frame.pack(); } }
核心代码三:测试成绩以及询问是否进行下一轮测试
import java.awt.event.*; import java.awt.*; import java.io.File; import java.io.FileWriter; import java.io.IOException; import javax.swing.*; /* * @auther:zhangkang * @time:2018.03.27 * function:Continue to test */ public class ContinuTest extends JFrame implements ActionListener{ JFrame jf; JPanel jp; JButton jb1,jb2,jb3; JLabel jlb1=null,jlb2=null,jlb3=null; JPanel jp1,jp2=null; DTimeFrame df2=new DTimeFrame(); Thread thread1=new Thread(df2); public ContinuTest(int sum) { String s=sum+""; jf = new JFrame(); jp = new JPanel(); jlb2=new JLabel("您本次测试成绩为:"); if(sum>60&&sum<=100){ jlb3=new JLabel(s+"分 "+"你真的太棒啦!"); } else{ jlb3=new JLabel(s+"分 "+"还要继续努力哦!"); } jlb1 = new JLabel("要不要再测试一次呢?"); jb1 = new JButton("当然要"); jb2 = new JButton("不要啦"); jb3=new JButton("查看测试结果"); jp1=new JPanel(); jp2=new JPanel(); jp1.add(jlb2); jp1.add(jlb3); jp1.add(jlb1); jp2.add(jb1); jp2.add(jb2); jp2.add(jb3); this.add(jp1); this.add(jp2); this.add(jp); jp1.setBounds(40,20,200,80); jp2.setBounds(40,100,200,100); jb1.addActionListener(this); jb2.addActionListener(this); jb3.addActionListener(this); this.setVisible(true); this.setResizable(false); this.setTitle("小学生四则运算"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setBounds(500, 200, 300, 220); } public void actionPerformed(ActionEvent e) { if (e.getActionCommand() == "当然要") { new UI(); this.dispose(); df2.setVisible(true); thread1.start(); } else if (e.getActionCommand() == "不要啦") { File f = new File("score.txt"); // 输入要删除的文件位置 if(f.exists()) f.delete(); df2.setVisible(false); thread1.stop(); this.dispose(); }else if(e.getActionCommand() == "查看测试结果"){ PrintChart pc=new PrintChart(); //读文件 ReadFile file = new ReadFile("score.txt"); String line = null; int[] score=new int[500]; int titleNum=0; while ((line = file.ReadLine()) != null) { titleNum++; score[titleNum]=Integer.parseInt(line); } pc.print(score,titleNum); file.close(); } } }
四、程序运行:程序运行时每个功能界面截图。
功能一:登录该系统界面
功能二:实现小学生四则运算(整数以及带括号题目)随机出题,点击开始答题按钮显示题目。
功能三:实现小学生四则运算答案生成以及成绩计算与显示
功能四:实现成绩测试柱状图
功能五:实现测试自动计时
功能六:实现询问是否进行下一轮测试
五、描述结对的过程,提供两人在讨论、细化和编程时的结对照片(非摆拍)。
我们在众创空间进行了讨论,主要针对界面的搭建以及成绩的计算详细地进行了讨论。这次的项目主要是针对小学生四则运算计算总成绩以及显示用时,可以对其进行成绩绘图,并且可以进行多轮测试。
具体思路是将出好的题目放置在txt文档中,随机抽取其中的二十道,并且每道题目不出现重复,题目的类型有百以内整数运算以及带括号算式,当然这次的题库文件是上次代码的运行结果,符合小学生计算要求; 在显示题目的同时进行时间的计时,答题结束后进行本次测试的成绩显示以及询问是否进行下一轮测试,若继续测试,则返回到出题界面,若不测试则退出界面;此外用户可以选择性地查看自己的测试成绩(以柱状图显示)。
六、结对作业的PSP。
PSP2.1 | 任务内容 | 计划共完成需要的时间(min) | 实际完成需要的时间(min) |
Planning | 计划 | 20 | 15 |
Estimate | 估计这个任务需要多少时间,并规划大致工作步骤 | 20 | 15 |
Development | 开发 | 470 | 500 |
Analysis | 需求分析 (包括学习新技术) | 10 | 10 |
Design Spec |
生成设计文档 |
15 | 20 |
Design Review | 设计复审 (和同事审核设计文档) | 5 | 10 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
Design | 具体设计 | 360 | 365 |
Coding | 具体编码 | 10 | 10 |
Code Review | 代码复审 | 20 | 25 |
Test | 测试(自我测试,修改代码,提交修改) | 30 | 30 |
Reporting | 报告 | 180 | 185 |
Test Report | 测试报告 | 10 | 10 |
Size Measurement | 计算工作量 | 20 | 20 |
Postmortem & Process Improvement Plan | 事后总结 ,并提出过程改进计划 | 150 | 155 |
七、请使用汉堡评价法给你的小伙伴一些点评。
在本次实验中我和我实验室里之前科研立项的项目组成员一起结对编程的。他的编程能力挺强的,总会有一些好的想法,在做这个项目之前,我将自己的一些界面设计的想法以及如何出题的想法和他说了,之后他利用一下午的时间设计并完善了出来,在我对代码进行整合的时候,发现还是有一些问题,我们就在学校众创空间进行了讨论,并对未完成的项目需求进行了分析与任务分配,当遇到问题时,比如结果的判断、两个函数之间参数的传递时及时进行了解决。总之,每个人都轻松地完成了实验任务。合作愉快,在编程中遇到棘手的问题,并没有急躁,以一种淡定的态度从容地解决问题,很赞。
八、结对编程真的能够带来1+1>2的效果吗?通过这次结对编程,请谈谈你的感受和体会。
答案是肯定的,结对编程可以带来1+1>2的效果。
在结对编程中两个人进行各自想法的分享。记得之前是为了避免出现机械的设计出题框的位置以及结果计算的判断,就想出了利用输入出题个数,然后显示题目并进行计算,但是后来发现一来题目要求是出20个计算题,二来是每次出题个数不一样,总分的设定也就不一样,那样绘制出来的柱状图就没有参考价值,所以就将这样的想法抛弃了;
此外在设计柱状图的时候,提出了将成绩保存在文本文档中,通过读取每行的成绩进行测试轮数的计算,之前我的想法是每次提交将提交次数加一,最后实际运行时发现这样是不能的,不管提交多少次提交次数总是一;
同时柱状图的每一次添加数据都需要区别对待,不然绘制出来的图只会在一个柱子上显示,所以使用addValue的时候第一个参数放置成绩第二个参数放置区别对待的属性比如分数1、分数2此类的,第三个参数放置测试的轮数,这样就将柱状图绘制了出来;
当用户不想继续测试退出时则需要将记录分数的文件删除以便于下一次测试时统计分数,避免出现未测试就已经有了成绩的情况。在测试的时候重新创建文件以记录测试成绩及测试轮数,便于绘制本次测试成绩的柱状图。
这样的交流避免了错误的发生,同时也加深了自己对该错误出现原因的理解。项目完成下来,少走了好多弯路,同时提高了效率,完美地完成了任务。
九、项目总结。
- 在实验过程中切身体会到了用户使用时的需求以及实际使用的操作方式,比如当我点击开始答题按钮时将题目显示并设置题目框不可以编辑,否则题目会出现更改,这样违背了测试的初衷,同时弹出计时框进行计时。
- 体会到了结对编程的好处,正如一句俗语所说“三个臭皮匠顶个诸葛亮”。
- 学习了Jfreechart绘图包的使用、时间线程的使用以及界面设置的基本方法。
- 测试界面布局改了好几天,愣是没发现出错的地方,第一个框一直在上边“飘着”。
- 最后借用《中庸》里边的一句话“行远自迩,登高自卑”。