关于家长的痛点
1.用户愿景:
随着生活节奏加快,加班和异地工作的人数逐渐增加,导致了许多问题的发生,主要因素在于分身乏术,不论是地理位置上的不便,还是时间上的不足,或者其他等原因,都导致的是家长难以对孩子进行看管,尤其是很多家长担心家里老人是否能监督的了孩子的学习。另一个令家长为难的事情是自己想监督辅导孩子的学习,不知如何下手。从学生的角度来看有一个可以练习习题的地方并不是一件坏事,更重要的一点是适时的给予家里的反馈使父母更加放心,很多时候学生想要时间上的自由,最简单的方法就是先把事情做了,而且还要被父母所看到。
2.需求分析:
家长的需求:查看孩子学习的进度
学生的需求:做题,简约的界面
用户场景:
需求更新:
界面要清新简约,功能操作简单
内容要有难度,知识点要全面,且具有一定深度
家长界面只显示成绩和记录即可
用户故事:
楚留香:成绩中上游,对于成绩的提升有着强烈的渴望,希望可以发现自己的短板继而弥补,家长对于他也基于厚望,期望成绩的提升。
段誉:成绩不好,对于提升成绩有着思想上的积极,行动上的消极,对于成绩快速提升有着不切实际的幻想,家长内心十分焦虑,极端渴望看到效果。
张无忌:成绩优秀,抱着以好奇,和扩充知识点的想法来使用,心态上更加平和,家长对于他的成绩比较放心。
段誉:对于成绩的波动,有着很大的反应,对于学生的成绩十分关心,希望每一步自己都能得到及时的反馈
杨过:关心孩子的学习,但也仅止于此,只关注成绩的结果,对于学习的过程缺乏有效地关心
乔峰:关心班里学生的成绩,担心有学生跟不上教学进度,希望学生能在课外追赶落后的进度
3.PSP个人流程图:
4.UML图:
5.代码:
package Frame; import java.awt.Color; import java.awt.Container; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.io.FileInputStream; import java.io.IOException; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Timer; import java.util.TimerTask; import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; //小学生一百以内加减法的演练窗体 public class MathEasyQuestion { private JFrame questionFrame=new JFrame();//创建窗体对象 private Container con = questionFrame.getContentPane();//获取窗体容器 private String projectPath =System.getProperty("user.dir")+"\WebContent";//获取项目中图片所在路径 private JPanel questionPanel=new JPanel();//口算练习 private int questionSum;//题目的数量 private int currentIndex=0;//当前题目所在数组的下标 private int firstError=0;//找到第一个出错题目的下标,没有则返回到0所在的题目 private int errorSum;//本次练习中错误的题目数量 private int rightSum=0;//本次练习中正确的题目数量 private String[] questions;//题目的内容 private String[] results;//题目的结果 private String[] resultUser;//用户输入的结果 private int[] statusNarrate;//状态描述 private JLabel questionNarrate=new JLabel();//题目描述 private JLabel questionLabel=new JLabel();//题目标签 private JTextField questionText=new JTextField();//输入结果文本框 private JLabel answerLabel=new JLabel();//答案标签 private JLabel resultLabel=new JLabel();//结果显示框 private JLabel statusLabel=new JLabel();//状态显示框 JLabel progressLabel=new JLabel();//进度条 private JButton submitButton=new JButton();//提交按钮 private JButton restartButton=new JButton();//重新测验按钮 private JButton precedingButton=new JButton();//上一题 private JButton nextButton=new JButton();//下一题 private JButton precedingPage=new JButton();//返回主窗口 private Timer timer=new Timer();//计时器 private JLabel timerLabel=new JLabel();//计时器标签 private int secondTime=0;//本次练习所花费的秒数 private String overtime;//格式化后的时间 private MainFrame mainFrame=new MainFrame();//主界面窗体 private JLabel conclusion=new JLabel();//结论 //练习题的标签 JLabel label7=new JLabel(); JLabel label8=new JLabel(); JLabel label9=new JLabel(); JLabel label10=new JLabel(); JLabel label11=new JLabel(); JLabel label12=new JLabel(); JLabel label13=new JLabel(); public MathEasyQuestion(int sum) { //定义数组和变量 questionSum=sum; questions=new String[sum]; results=new String[sum]; resultUser=new String[sum]; statusNarrate=new int[sum]; errorSum=questionSum; generateQuestions(sum);//生成指定数量的题目 questionFrame.setTitle("乐学"); questionFrame.setVisible(true); int width = Toolkit.getDefaultToolkit().getScreenSize().width; int height = Toolkit.getDefaultToolkit().getScreenSize().height; // 定义窗体的宽高 int windowsWedth = 500; int windowsHeight = 500; Image m = null; try { m = ImageIO.read(new FileInputStream(projectPath+"\head\astronaut.jpg")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } questionFrame.setIconImage(m); questionFrame.setBounds((width - windowsWedth) / 2, (height - windowsHeight) / 2, windowsWedth, windowsHeight); questionFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); questionFrame.setVisible(true); questionFrame.setLayout(null); questionFrame.setResizable(false); questionsPanel(); setTimer(); } //创建包含控件的Panel对象 private void questionsPanel() { questionPanel.setBounds(50,60,390,330); questionPanel.setBackground(Color.white); questionPanel.setVisible(true); questionPanel.setLayout(null); //Border mathBorder=new Border(); questionPanel.setBorder(BorderFactory.createTitledBorder("口算练习")); setStatusLabel(); setQuestionScale(); setSubmitButton(); setPrecedingButton(); setNextButton(); setProgress(); setPrecedingPage(); setRestartButton(); setTimerLabel(); con.add(questionPanel); } //练习的原始状态设置 并为用户输入框添加事件获取值 private void setQuestionScale() { questionLabel.setBounds(50,70,70,30); questionLabel.setText("<html><body><p style='font-size:14px;'>"+"题目:"+"</p></body></html>"); answerLabel.setBounds(50,120,70,30); answerLabel.setVisible(false); answerLabel.setText("<html><body><p style='font-size:14px;'>"+"答案:"+"</p></body></html>"); questionNarrate.setBounds(120,70,100,30); questionNarrate.setText("<html><body><p style='font-size:14px;'>"+questions[currentIndex]+"</p></body></html>"); questionText.setBounds(200,75,80,30); questionText.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent arg0) { // TODO Auto-generated method stub } //一旦文本框失去焦点则将文本框内的内容写进数组 @Override public void focusLost(FocusEvent arg0) { // TODO Auto-generated method stub resultUser[currentIndex]=questionText.getText(); }}); resultLabel.setBounds(120,120,80,30); resultLabel.setVisible(false); resultLabel.setText("<html><body><p style='font-size:14px;'>"+String.valueOf(results[currentIndex])+"</p></body></html>"); questionPanel.add(questionNarrate); questionPanel.add(questionText); questionPanel.add(resultLabel); questionPanel.add(questionLabel); questionPanel.add(answerLabel); } //设置重新开始按钮 private void setRestartButton() { restartButton.setBounds(160,260,80,30); restartButton.setVisible(false); restartButton.setText("继续"); restartButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub questionFrame.dispose(); new MathEasyQuestion(questionSum); } }); questionPanel.add(restartButton); } //设置计时器 private void setTimer() { timer.schedule(new TimerTask() { @Override public void run() { // TODO Auto-generated method stub secondTime+=1;//计时器自动叠加秒数 long millisecond=secondTime*1000;//将秒数转为毫秒数 SimpleDateFormat formatter = new SimpleDateFormat("mm:ss");//设置时间格式 overtime=formatter.format(millisecond); timerLabel.setText("<html><body><p style='font-size:14px;'>时间:"+overtime+"</p></body></html>"); }}, 1000, 1000);//延迟一秒 间隔一秒 } //设置计时器标签 private void setTimerLabel() { timerLabel.setBounds(240,20,210,30); timerLabel.setText("<html><body><p style='font-size:14px;'>时间:"+String.valueOf(secondTime)+"</p></body></html>"); questionPanel.add(timerLabel); } //设置包含对错图形的标签,并设置为不可见 private void setStatusLabel() { statusLabel.setBounds(320,70,30,30); statusLabel.setVisible(false); questionPanel.add(statusLabel); } //为对错标签添加图片 private void setStatusPicture(String picture) { Image image = Toolkit.getDefaultToolkit().getImage(projectPath+picture); ImageIcon icon=new ImageIcon(image); icon.setImage(icon.getImage().getScaledInstance(statusLabel.getWidth(),statusLabel.getHeight(),Image.SCALE_DEFAULT )); statusLabel.setIcon(icon); } //设置交卷后的综合评价标签 private void setConclusion(String words) { conclusion.setBounds(100,160,300,70); conclusion.setVisible(true); conclusion.setText(words); questionPanel.add(conclusion); } //设置当前题目页数与总的题目页数 private void setProgress() { progressLabel.setBounds(180,20,50,30); progressLabel.setText("<html><body><p style='font-size:14px;'>"+(currentIndex+1)+"/"+questionSum+"</p></body></html>"); questionPanel.add(progressLabel); } //设置提交按钮,计算用户输入的值是否正确,将一些标签设置为可见,显示结果 private void setSubmitButton() { submitButton.setBounds(160,260,80,30); submitButton.setText("交卷"); submitButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub timer.cancel(); comparison(); statusLabel.setVisible(true); answerLabel.setVisible(true); resultLabel.setVisible(true); conclusion.setVisible(true); //交卷后下标将回到第一个出错的页面,全对则到第一道题所在的页面 for(int z=0;z<questionSum;z++) { if(statusNarrate[z]==1) { firstError=z; break; } } currentIndex=firstError; changeQuestion(); //设置用户输入框为不可修改 questionText.setEditable(false); //显示测试结果以及评价 double rightRate; if(errorSum==0) { rightRate=1; }else if(rightSum==0) { rightRate=0; }else { rightRate=(double)(Math.round((rightSum/questionSum)*100))/100; } setConclusion("<html><body><p style='font-size:11px;'>正确的数量:"+rightSum+"    " + "错误的数量:"+errorSum+"<br>" + "准确率:"+rightRate+"    " + "耗费时长:" +overtime + "<br>评语:" +evaluate(rightRate)+"</p></body></html>"); //设置交卷按钮为不可见,并设置开始按钮为可见 submitButton.setVisible(false); restartButton.setVisible(true); }}); questionPanel.add(submitButton); } //根据正确率来进行评价 private String evaluate(double rightRate) { if(rightRate==1) { return "太棒了!全对了"; }else if(rightRate>0.9) { return "距离完美只差一点点了"; }else if(rightRate>0.8) { return "看来我们需要更多的练习了"; }else if(rightRate>0.6) { return "看来我们并不是只有表面的差距"; }else if(rightRate>0.3) { return "不放弃,每一步,都是胜利"; }else { return "不要气馁!还有希望"; } } //比较用户输入的值和题目的答案 private void comparison() { for(int i=0;i<questionSum;i++) { if(results[i].equals(resultUser[i])) { statusNarrate[i]=0;//0表示正确 errorSum-=1; rightSum+=1; }else { statusNarrate[i]=1;//1表示错误 } } } //创建上一题按钮,并添加事件,改变标签的内容和图片 private void setPrecedingButton() { precedingButton.setBounds(50,260,80,30); precedingButton.setText("上一题"); questionPanel.add(precedingButton); precedingButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub if(currentIndex!=0) { currentIndex-=1;//改变题目的下标 changeQuestion(); } } }); } //创建上一题按钮,并添加事件,改变标签的内容和图片 private void setNextButton() { nextButton.setBounds(260,260,80,30); nextButton.setText("下一题"); nextButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub if(currentIndex!=(questionSum-1)) { currentIndex+=1;//改变题目的下标 changeQuestion(); } } }); questionPanel.add(nextButton); } //跳转到currentIndex值指定的界面 private void changeQuestion() { questionNarrate.setText("<html><body><p style='font-size:14px;'>"+questions[currentIndex]+"</p></body></html>"); resultLabel.setText(String.valueOf("<html><body><p style='font-size:14px;'>"+results[currentIndex])+"</p></body></html>"); progressLabel.setText("<html><body><p style='font-size:14px;'>"+(currentIndex+1)+"/"+questionSum+"</p></body></html>"); //在切换题目的时候,如果是之前写过的内容则显示在文本框 if(resultUser[currentIndex]!=null) { questionText.setText(String.valueOf(resultUser[currentIndex])); }else { questionText.setText(""); } //questionText.setText("");//更换题目之后将文本框清空 if(statusNarrate[currentIndex]==0) { setStatusPicture("\head\right.jpg");//0表示正确 }else if(statusNarrate[currentIndex]==1){ setStatusPicture("\head\fail.jpg");//1表示正确 } } //生成一百以内加减法的题目 public void generateQuestions(int index) { for(int i=0;i<index;i++) { int j=(int)(1+Math.random()*(100-1+1)); int z=(int)(1+Math.random()*(100-1+1)); if(j-z<100&&j-z>0) { questions[i]=String.valueOf(j)+"-"+String.valueOf(z); results[i]=String.valueOf(j-z); }else if(j+z<100&&j+z>0) { questions[i]=String.valueOf(j)+"+"+String.valueOf(z); results[i]=String.valueOf(j+z); }else if(z-j<100&&z-j>0) { questions[i]=String.valueOf(z)+"-"+String.valueOf(j); results[i]=String.valueOf(z-j); } } } //设置返回主界面按钮 private void setPrecedingPage() { precedingPage.setBounds(50,25,100,30); precedingPage.setText("《=主界面"); precedingPage.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub questionFrame.dispose(); mainFrame.loadmain(); }}); questionPanel.add(precedingPage); } public static void main(String[] args) { MathEasyQuestion meq=new MathEasyQuestion(5); } }
6:示例图