一、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()等系统函数获取相应时间。
-
View Code
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 }