四则运算生成程序——GUI支持和部分功能改进
工程地址:
https://coding.net/u/jx8zjs/p/paperOne/git
ssh://git@git.coding.net:jx8zjs/paperOne.git
需求:
1.GUI支持:用户界面新增支持 Windows GUI,同时保留原有命令行下所有功能。
2.配置文件:提供用户可用文本编辑器修改的配置文件,在其中包括用户名、总答题数、答错题数。
3.错题本:可回放做错的题目,提供再次练习的机会/删除特定错题。
变更:
1.支持倒计时:答题模式出题以后会自动计时,如果用未在规定时间内答完题目则会自动被提交试卷,答题时间和题目数量等相关。
2.出题数目:变更前的版本会因为出题数量过多而界面显示不下,已改进为滚动模式防止溢出。
3.错题本:错题本完善,可以记录错题,数量,甚至从错题本中抽取题目重做,也可以将错题本中的题目选择性删除。
4.更详细的配置内容显示和编辑:记录用户名、总答题数、答错题数,可以编辑这些信息。
设计:
1.倒计时:使用单例模式线程,每秒缩减答题时间一秒,倒计时时间到则触发提交按钮完成抢卷功能,选择单例模式也是防止多次生成题目导致倒计时速度加快的问题。
2.变更前使用的Jpanel控件和MigLayout,这样可以方便显示题目并且可以控制题目格式布局,不过题目过大需要手动调节窗口,否则会有部分题目超出浏览范围。改进后使用JScrollPane,并设置为MigLayout,同样达到了控制布局的效果,也能将原来显示不下的题目通过滚动条拖拽的方式显示出来。
3.打开错题本可以看到每道错题前均有复选框用于删除题目,错题删除采用JCheckBox在题目前显示,根据勾选情况获取到题目的编号进行删除,最后再重写到错题本中。
4.点击编辑信息按钮则在工作区显示编辑的项目,提交即可。
部分代码实现:
1.1倒计时实现:
1 class MyThread extends Thread { 2 private MyThread(){ 3 4 } 5 private static MyThread instance =null; 6 public static MyThread getInstance(){ 7 if(instance==null){ 8 instance = new MyThread(); 9 } 10 return instance; 11 } 12 public void run() { 13 while (MainWindow.time > 0) { 14 MainWindow.time--; 15 MainWindow.lblTime.setText(MainWindow.time + ""); 16 try { 17 Thread.sleep(1000); 18 } catch (Exception e) { 19 e.printStackTrace(); 20 } 21 if (MainWindow.subOnClick == 1) { 22 return; 23 } 24 25 } 26 27 MainWindow.submitButton.doClick(); 28 29 } 30 }
1.2倒计时的使用:生成题目后加入此段代码,保证只创建一个计时线程,并且线程不会被重复启动
1 try{ 2 MyThread.getInstance().start(); 3 }catch (Exception e1) { 4 // TODO: handle exception 5 }
2.带有滚动条的题目显示面板:然后题目加入到包裹在JScrollpane下的Jpanel中,减少对原有代码的修改量
1 private JScrollPane scrollPane = new JScrollPane(); 2 scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 3 scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 4 frmPaperone.getContentPane().add(scrollPane, BorderLayout.CENTER); 5 6 scrollPane.add(panelMain); 7 panelMain.setLayout(new MigLayout("", "[][grow]", "[][]")); 8 scrollPane.setViewportView(panelMain);
3.错题本的编辑和题目删除:
1 // 错题本按钮 2 buttonWrong.addActionListener(new ActionListener() { 3 @Override 4 public void actionPerformed(ActionEvent e) { 5 // 初始化 6 subOnClick = 1; 7 panelMain.removeAll(); 8 frmPaperone.repaint(); 9 int m = 0; 10 int num = Wrong.size(); 11 for (int i = 0; i < num; i++) { 12 String[] wrong = Wrong.get(i); 13 JCheckBox chckbxNewCheckBox = new JCheckBox(""); 14 // chckbxNewCheckBox.setText(wrong[0] + "=" + wrong[1]); 15 panelMain.add(chckbxNewCheckBox, "cell 0 " + m + ",alignx trailing"); 16 17 JLabel wrongBar = new JLabel(""); 18 panelMain.add(wrongBar, "cell 1 " + m + ",alignx 0"); 19 wrongBar.setText(wrong[0] + "=" + wrong[1]); 20 m++; 21 } 22 // 删除按钮 23 ArrayList<Integer> al = new ArrayList<>(); 24 btnDelete.addActionListener(new ActionListener() { 25 public void actionPerformed(ActionEvent e) { 26 27 Component[] compnent = panelMain.getComponents(); 28 for (int i = 0; i < num * 2; i++) { 29 try { 30 JCheckBox tmp = (JCheckBox) compnent[i]; 31 if (tmp.isSelected()) { 32 al.add(i / 2); 33 } 34 } catch (Exception e1) { 35 continue; 36 } 37 } 38 for (int d = al.size() - 1; d >= 0; d--) { 39 Wrong.remove(Wrong.get(al.get(d))); 40 } 41 messageBar.setText("删除成功!"); 42 RewriteNote(); 43 al.clear(); 44 frmPaperone.repaint(); 45 buttonWrong.doClick(); 46 } 47 }); 48 49 panelMain.add(btnDelete, "cell 1 " + m + ",alignx trailing"); 50 51 } 52 });
4.编辑用户信息:
1 // 修改信息按钮 2 3 btnEdit.addActionListener(new ActionListener() { 4 @Override 5 public void actionPerformed(ActionEvent e) { 6 panelMain.removeAll(); 7 panelMain.add(lblUserNameEdit, "cell 0 0,alignx trailing"); 8 9 textFieldUs.setText(username); 10 panelMain.add(textFieldUs, "cell 1 0,alignx trailing"); 11 textFieldUs.setColumns(10); 12 13 panelMain.add(lblNumRightEdit, "cell 0 1,alignx trailing"); 14 15 panelMain.add(NumSumEdit, "cell 1 1,alignx trailing"); 16 NumSumEdit.setText(SumOfA + ""); 17 18 panelMain.add(lblNumWrongEdit, "cell 0 2,alignx trailing"); 19 20 panelMain.add(NumWrongEdit, "cell 1 2,alignx trailing"); 21 NumWrongEdit.setText(SumOfE + ""); 22 23 panelMain.add(reButton, "cell 0 3,alignx trailing"); 24 panelMain.add(saveButton, "cell 1 3,alignx trailing"); 25 subOnClick = 1; 26 panelMain.repaint(); 27 } 28 }); 29 30 // 保存按钮 31 saveButton.addActionListener(new ActionListener() { 32 @Override 33 public void actionPerformed(ActionEvent e) { 34 panelMain.removeAll(); 35 36 username = textFieldUs.getText(); 37 messageBar.setText("用户名已修改为" + username); 38 UserName.setText(username); 39 RewriteNote(); 40 41 frmPaperone.repaint(); 42 } 43 44 }); 45 46 // 重置按钮 47 reButton.addActionListener(new ActionListener() { 48 @Override 49 public void actionPerformed(ActionEvent e) { 50 panelMain.removeAll(); 51 52 SumOfA = 0; 53 SumOfE = 0; 54 Wrong.clear(); 55 messageBar.setText("重置成功"); 56 NumSum.setText(SumOfA + ""); 57 NumWrong.setText(SumOfE + ""); 58 RewriteNote(); 59 60 frmPaperone.repaint(); 61 62 } 63 64 });
运行截图:
打开程序选择编辑按钮
将用户名修改
变更成功
出题10道,简单难度答题时间60秒,7秒后变为53秒
简单难度50道题目,总答题时间为260秒,侧边滚动条可以拖拽显示原本超出屏幕的内容。
打开错题本
删除其中的前三道题目
删除错题本选中的错题后将剩余的题目作为试卷出题,达到错题重做的目的。
难度设置
结对体会:
面对不同的需求可能两个人会有不同的解决方案,也许会想出非常简单的设计方法让其实现简单化。在设计程序的交互上也采取尽量不弹框的原则,将要提示的内容显示在程序的状态栏上,省去用户的冗余点击事件也算是友好交互的探索。
花费时间较长的问题:排版(Layout)问题。
工程地址:
https://coding.net/u/jx8zjs/p/paperOne/git
ssh://git@git.coding.net:jx8zjs/paperOne.git