四则运算结对项目之GUI

    本次结对编程让我学到了许多许多知识,受益不浅!在此以前,我没想过我能作出一个双击运行的小程序。html

    感谢个人队友与我同心合力,感谢室友宇欣告诉我操做符为“最多多少”而不是“多少”并教我使用效能分析工具,感谢陈杰任劳任怨帮我测试14寸显示屏效果,感谢福孝大佬给我发的安装包!感谢学姐对项目的建议!java

    代码仓库地址:https://git.coding.net/Siamese_miao/team.gitgit

    本人:庄莉,学号:2016012034算法

    队友:王璐瑶,学号:2016012095编程


 

计划PSP

PSP小程序

任务内容数组

计划共完成须要的时间(h)多线程

Planningapp

计划dom

0.5

Estimate

   估计这个任务须要多少时间,并规划大体工做步骤

0.5

Development

开发

39.25

   Analysis

需求分析 (包括学习新技术)

0.5

Design Spec

  生成设计文档

0.25

  Design Review

设计复审 (和同事审核设计文档)

0.25

Coding Standard

 代码规范 (为目前的开发制定合适的规范)

0.25

 Design

 具体设计

2

Coding

具体编码

30

Code Review

 代码复审

1

Test

测试(自我测试,修改代码,提交修改)

5

Reporting

报告

4

Test Report

测试报告(包括博客)

3

 Size Measurement

计算工做量

0.5

Postmortem & Process Improvement Plan

过后总结, 并提出过程改进计划

0.5

 


 

结对编程对接口的设计

信息隐藏(Information Hiding)

    Information hiding is part of the foundation of both structured design and object-oriented design. In structured design, the notion of “black boxes” comes from information hiding. In object-oriented design, it gives rise to the concepts of encapsulation and modularity, and it is associated with the concept of abstraction.

    在《代码大全》中列出了两类须要隐藏的内容:

    第一类信息是复杂化的信息。对于咱们的项目,咱们的main函数只有一个对gui的实例化,使用者并不知道内部的运行方式。内部的算法实现封装起来,外部只有调用的接口,只能够调用方法,不能够改变内部变量,作到了信息隐藏。

    对于第二类,是指变更的信息。好比在用户的输入需求中出现了错误,提示并返回,这个错误在类中进行了适当的处理,错误没有扩散,这样能够提升程序的容错性。

接口设计(Interface Design)

    在本项目设计接口过程当中,按需求新建接口,使用明确的命名方式使接口的功能清晰化,加强了可读性;接口与接口之间互相独立,使用方便。

松耦合(Loose coupling)

    耦合的强度依赖于:(1)一个模块对另外一个模块的调用;(2)一个模块向另外一个模块传递的数据量;(3)一个模块施加到另外一个模块的控制的多少;(4)模块之间接口的复杂程度。等等。

    模块内子程序(下一个层次上)应共享数据(有必定的耦合度),而减小全局变量能下降子程序性间的耦合性。

  类与类之间一般经过接口的契约实现服务提供者/服务请求者模式,这就是典型的松耦合。

    耦合程度越高,模块与模块之间的联系性就更高,系统的灵活性就越低,报错率就更高。在咱们的项目中,计算模块的调用都比较单一,没有双向调用,使用之间互不干扰,增长了灵活性。

 


 

计算模块接口的设计与实现过程

    通过商讨,咱们决定基于个人我的项目修改。我先删除了原来的分数运算,在将普通四则运算与括号四则运算拆分,变成简单加减、四则运算、有括号加减与有括号四则运算。如图我分为5个类(test为单元测试)。

  • Command类:命令行测试类,负责接收命令行的参数并启动程序。
  • fileCreate类:建立文件类,负责产生result.text文件,将练习题写入文件以及作题模式的生成记录。
  • formula类:式子类,负责根据调用产生同种类型的式子,含有AddSubtract(加减运算)、arithmetic(简单四则运算)、Bracket(带括号的四则运算)、Bracket_AS (带括号的加减运算)四种函数。
  • calculate类:计算类,负责各类计算,含有有条件产生后一位数、有条件操做符等7个方法。
  • stack类:栈,负责计算式子,并判断式子合法性。

    其中,有条件生成操做符与后一位数我较为满意,它大大的下降了运行效率,部分代码可看第5模块的性能改进模块。

 


 

计算模块接口部分的性能改进

    基于原来的我的项目代码,因为出现了运算过程以及运算结果数值范围的限制,本来的result(String temp)再也不使用,改用了栈运算。

 1 // 计算结果  2 public static Object result(String temp) {  3 ScriptEngineManager sem = new ScriptEngineManager();  4 ScriptEngine se = sem.getEngineByName("js");  5 Object last = 0;  6 try {  7 last = se.eval(temp);  8 } catch (ScriptException e) {  9  e.printStackTrace(); 10  } 11 return last; 12 }
result函数

    在栈的运算中加入判断

1 if (Math.abs(sresulat) > upper || Math.abs(sresulat) < lower) 2 { 3 return 0; 4 }
判断

    而对于简单加减无括号全程不改变优先级的运算则不过栈,直接边生成数字便运算,减小了运算时间。

    另外,本来的操做符是一开始随机生成好的再判断选择后一个数,而后再判断符号是否合法,再修改符号,若是仍是有小数或负数,则从新运行生成算式的函数,这样使得代码运行有些慢且屡次运行。再加上数值范围的限定以及能够存在负数,我改变了想法。

    由于负数的存在,使得加减号并无数字的限制,而乘法有上限限制,除法有下限限制。因此在只有加减的运算中,符号随机生成,后一个数根据运算符以及数值范围生成合法的数。

 1 // 相加不超过范围  2 public static int decide0(int x, int min, int max)  3  {  4 int y;  5 int temp = 0;  6 if (x > 0)  7  {  8 temp = max - min - x + 1;// 加一个正整数范围  9 } else 10  { 11 temp = max - (min - x) + 1;// 加至正整数的范围 12  } 13 if (temp < 0) 14 {// 范围小于0 15 if (x > 0) 16  { 17 temp = Math.abs(x) - min * 2 + 1;// 正整数过大,需加负数 18 y = 0 - (int) (Math.random() * temp) - min; 19 } else 20  { 21 temp = Math.abs(x) - 2 * min + 1;// 负数太小,越值,加小整数至负数范围 22 y = (int) (Math.random() * temp) + min; 23  } 24 } else 25  { 26 y = (int) (Math.random() * temp + min); 27  } 28 return y; 29  } 30 31 // 相减不小于最小 32 public static int decide1(int x, int min, int max) 33  { 34 int temp = 0; 35 int y = 0; 36 if (x > 0) 37  { 38 temp = x - 2 * (min - 1) - 1; // 减一个正数范围 39 } else 40  { 41 temp = max + x - min + 1;// 减一个正数范围 42  } 43 if (temp > 0) 44  { 45 if (x < 0 && temp < min) 46  { 47 temp = Math.abs(x) - 2 * min + 1;// 负数太小,需减负数 48 y = 0 - (int) (Math.random() * temp) - min; 49 } else 50  { 51 y = (int) (Math.random() * temp + min); 52  } 53 } else 54  { 55 temp = max - x - min + 1;// 只有x>0的状况会出现,正数太小,需减负数 56 y = 0 - (int) (Math.random() * temp) - min; 57  } 58 return y; 59 }
加减法的后一位数选定

    当有乘除时,则根据上一个数生成操做符,再根据操做符生成合法的后一位数。

 1 // 操做符的选定  2 public static int operator(int num, int middle2, int middle3)  3  {  4 if (Math.abs(num) <= middle2)  5 {// 除法下界  6 if (Math.abs(num) < middle3)  7  {  8 return 3;  9 } else 10  { 11 return 0; 12  } 13 } else if (Math.abs(num) >= middle3) 14 {// 乘法上界 15 return 2; 16 } else 17  { 18 return (int) (Math.random() * 4); 19  } 20  } 21 // 下一位数字的选定 22 public static int[] numberB(int key, int num, int lower, int upper) 23  { 24 int[] find = new int[] { 0, lower }; 25 if (key == 0) 26  { 27 find[1] = decide0(num, lower, upper); 28 return find; 29 } else if (key == 2) 30  { 31 int[] judge = new int[2]; 32 judge = decide2(num, lower);// 确保可以整除,并不低于下限 33 if (judge[0] == 0) 34  { 35 find[1] = judge[1]; 36 return find; 37 } else 38  { 39 find[0] = 1; 40  } 41 } else if (key == 3) 42  { 43 find[1] = decide3(num, lower, upper); 44 if (find[0] == 0) 45  { 46 return find; // 乘法不超过上限 47  } 48  } 49 find[1] = decide1(num, lower, upper); 50 return find; 51 }
操做符选定以及下一位数字的选定

    这样大大减小了从新调用函数的问题,而且实现了运算过程与数值皆在范围内的功能。

    在附加题记录用户模块,一开始使用contains(name)函数判断用户,后来发现这样会出现abc与abcabc被认为同一我的而的状况,通过思考,咱们使用字符串的断开。

  1 String[] arrays = txt.split(" "); 

    再使用equals(String)函数判断用户,解决了这个问题。

    其中,生成有括号与乘除的式子生成的函数判断耗时最多,由于它的判断较多,限制较多,优先级易改变,容易生成最终不合法的式子而从新运行。

 1 // 带括号的四则运算  2 public static String Bracket(int lower, int upper, int o) {  3 int middle2 = lower * lower;// 除法下界  4 int middle3 = upper / lower;// 乘法上界  5 int brack_left = 0; // 记录未匹配的左括号个数  6 int brack = 0; // 括号个数  7 int j = 0;  8 char[] p = new char[] { '+', '-', '÷', '*' };  9 String temp1 = ""; 10 int[] num = new int[o + 1]; // 数字 11 int[] key = new int[o]; // 符号所在的下标 12 num[0] = (int) (Math.random() * (upper - lower + 1) + lower); 13 int result; 14 int[] find = new int[2]; 15 for (j = 0; j < (o - 1); j++) { 16 if (num[j] < 0) { 17 temp1 += "(" + String.valueOf(num[j]) + ")"; 18 } else { 19 temp1 += String.valueOf(num[j]); 20  } 21 int tmpcnt = brack_left; 22 for (int i = 0; i < tmpcnt; i++) { // 若当前有未匹配的左括号,则对每个未匹配的左括号,都有必定几率生成相应右括号。 23 if ((int) (Math.random() * 5) > 1) { // 生成右括号几率为0.6 24 brack_left--; 25 temp1 += ")"; 26  } 27  } 28 key[j] = calculate.operator(num[j], middle2, middle3); 29 find = calculate.numberB(key[j], num[j], lower, upper); 30 if (find[0] == 1) { 31 key[j] = 1; 32  } 33 num[j + 1] = find[1]; 34 temp1 += String.valueOf(p[key[j]]); 35 if (((brack * 2) <= o) && (((int) (Math.random() * 2)) == 0)) { // 以必定几率生成左括号,几率为1/2 36 temp1 += "("; 37 brack++; 38 brack_left++; 39 j++; 40 if (num[j] < 0) { 41 temp1 += "(" + String.valueOf(num[j]) + ")"; 42 } else { 43 temp1 += String.valueOf(num[j]); 44 } // 生成左括号后必须生成一个数字和运算符,否则可能出现(15)这样的错误 45 key[j] = calculate.operator(num[j], middle2, middle3); 46 find = calculate.numberB(key[j], num[j], lower, upper); 47 if (find[0] == 1) { 48 key[j] = 1; 49  } 50 num[j + 1] = find[1]; 51 temp1 += p[key[j]]; 52  } 53  } 54 while (j != o) { // 判断是否为最后一个数 55 if (num[j] < 0) { 56 temp1 += "(" + String.valueOf(num[j]) + ")"; 57 } else { 58 temp1 += String.valueOf(num[j]); 59  } 60 key[j] = calculate.operator(num[j], middle2, middle3); 61 temp1 += p[key[j]]; 62 find = calculate.numberB(key[j], num[j], lower, upper); 63 if (find[0] == 1) { 64 key[j] = 1; 65  } 66 j++; 67 num[j] = find[1]; 68  } 69 if (num[o] < 0) { 70 temp1 += "(" + String.valueOf(num[o]) + ")"; 71 } else { 72 temp1 += String.valueOf(num[o]); 73  } 74 while ((brack_left) != 0) { // 补全右括号 75 temp1 += ")"; 76 brack_left--; 77  } 78 result = stack.work(temp1, lower, upper, 1); 79 if (result == 0) { 80 temp1 = Bracket(lower, upper, o); 81  } 82 return temp1; 83 84  } 85 86 }
有括号四则运算

    项目整体分析图,从内存,多线程,CPU等方面分析了计算模块的性能,截图以下:

     性能分析过程截图:

     按F4,出现如下截图。资源所有被回收。证实没有资源泄露。程序性能良好。

      使用单元测试的CPU分析以下图:

    使用Command.java的CPU效能分析以下图: 

 


 

单元测试

1  @Test 2     public void testWork() { 3         assertEquals(0, stack.work("7-5÷(1*37)÷(1*83)", 1, 900, 1)); 4         assertEquals(30, stack.work("55+(-25)÷5*(20-15)", 2, 300, 1)); 5         assertEquals(80, stack.work("((55+25)÷5)*(20-15)", 2, 300, 1)); 6         assertEquals(0, stack.work("60*(20-15)", 2, 200, 1)); 7     }
栈的测试

    第一个断言测试的是没法整除返回错误标志0;

    第二个断言测试的是负数运算;

    第三个断言测试的是特殊括号位置的运算;

    第四个断言测试的是超过数值返回错误标志0。

 1 @Test  2 public void testAll() {  3 // 顺序不一样以及异常测试。生成的文件会被覆盖。  4 String[] arg0 = new String[] { "-n", "100", "-m", "5", "100", "-o", "3", "-c", "-b" };  5 String[] arg1 = new String[] { "-m", "5", "50", "-o", "3", "-n", "100", "-c" };  6 String[] arg2 = new String[] { "-o", "3", "-m", "5", "50", "-n", "100", "-b" };  7 String[] arg3 = new String[] { "-n", "100", "-o", "3", "-m", "5", "50" };  8 Command.main(arg0);// 有括号四则运算测试  9 Command.main(arg1);// 四则运算测试 10 Command.main(arg2);// 有括号加减运算测试 11 Command.main(arg3);// 加减运算测试 12 }
命令行正确输入测试

    该部分测试的命令行的更改输入顺序的四种出题选择正常运行。输入异常部分请看第七点。

    命令行单元测试覆盖率截图以下:

1 @Test 2 public void testDecide2() { 3 int[] find = new int[2]; 4 find = calculate.decide2(20, 2); 5 assertEquals(2, find[1]); 6 find = calculate.decide2(13, 2); 7 assertEquals(1, find[0]); 8 }
除法选择除数测试

    decide2(int x, int min)为除法选择除数的函数,函数以下:

 1 // 被除数能被除数整除并不低于最小  2 public static int[] decide2(int x, int min)  3  {  4 int[] judge = new int[] { 1, 0 };  5 int temp = Math.abs(x) / min - min + 1;// 除数的范围  6 for (int i = min; i < (temp + min); i++)  7  {  8 if (Math.abs(x) % i == 0)  9 {// 判断是否整除 10 judge[0] = 0; 11 judge[1] = i; 12 return judge; 13  } 14  } 15 return judge; 16 }
decide2函数

    其中,judge[0]用于判断该数可否有可整除的除数,1为没有,0为有,judge[1]为除数的值。该单元测试则测试了一次可产生除数与一次不能产生除数的状况。

 


 

异常说明

 1 @Test  2 public void testAll() {  3 String[] arg4 = new String[] { "-o", "3", "-m", "5", "50", "-n" };  4 String[] arg4_1 = new String[] { "-o", "3", "-n", "-m", "5", "50" };  5 String[] arg4_2 = new String[] { "-n", "100000", "-m", "5", "50" };  6 String[] arg4_3 = new String[] { "-o", "3", "-m", "5", "50" };  7  8 String[] arg5 = new String[] { "-n", "50" };  9 String[] arg5_1 = new String[] { "-m", "5", "-n", "50", "-o", "3" }; 10 String[] arg5_2 = new String[] { "-n", "50", "-m", "3" }; 11 String[] arg5_3 = new String[] { "-n", "50", "-o", "3", "-m" }; 12 String[] arg5_4 = new String[] { "-m", "-n", "50" }; 13 14 String[] arg6 = new String[] { "-o", "11", "-m", "5", "50", "-n", "100" }; 15 String[] arg6_1 = new String[] { "-n", "100", "-o", "-m", "5", "50" }; 16 String[] arg6_2 = new String[] { "-n", "100", "-m", "5", "50", "-o" }; 17 18 String[] arg7 = new String[] { "-m", "5", "20", "-n", "100", "-c" }; 19 String[] arg7_1 = new String[] { "-m", "5", "50", "-n", "100", "-b" }; 20 21 String[] arg8 = new String[] { "-b", "1", "-o", "3", "-m", "5", "50", "-n", "100" }; 22 String[] arg8_1 = new String[] { "-c", "1", "-o", "3", "-m", "5", "50", "-n", "100" }; 23 String[] arg8_2 = new String[] { "-n", "100", "-m", "5", "50", "-d" }; 24 25 Command.main(arg4);// 缺乏题数值测试 26  Command.main(arg4_1); 27 Command.main(arg4_2);// 题数值过大测试 28 Command.main(arg4_3);// 缺乏题数测试 29 30 Command.main(arg5);// 缺乏数值范围 31 Command.main(arg5_1);// 缺乏数值范围上限测试 32  Command.main(arg5_2); 33 Command.main(arg5_3);// 缺乏数值范围上下限测试 34  Command.main(arg5_4); 35 36 Command.main(arg6);// 操做符数值过大测试 37 Command.main(arg6_1);// 缺乏操做符数值测试 38  Command.main(arg6_2); 39 40 Command.main(arg7);// 乘除须要上界大于下界的平方 41 Command.main(arg7_1);// 括号须要操做符数大于1 42 43 Command.main(arg8);// 输入非法测试之b后有数字 44 Command.main(arg8_1);// 输入非法测试之c后有数字 45 Command.main(arg8_2);// 输入非法测试之无辨识字符 46 }
命令行异常输入测试

    对于命令行可能出现的异常大概有13个:

  • 缺乏题数值(-n后无带数字,如arg4与arg4_1)时,提醒缺乏题数值,并告知-n的范围;

  • 题数值过大(-n后数值超过10000,如arg4_2)时,提醒告知题数值范围(太小同理);

  • 缺乏题数(命令中无-n,如arg4_3)时,提醒-n为必须项,并告知-n范围。

  • 缺乏数值范围(命令中无-m,如arg5)时,提醒-m为必须项,并告知-m上下限各自范围;

  • 缺乏数值范围上限(-m后只带一个数字,如arg5_1和 arg5_2)时,提醒缺乏上限,并告知上限范围;

  • 缺乏数值范围上下限(-m后不带数字,如arg5_3和 arg5_4)时,提醒缺乏上下限,并告知上下限各自范围;

  • 数值范围数值太小过大时,提醒告知操做符数值范围。

  • 操做符数值过大(-o后数值超过10,如arg6)时,提醒告知操做符数值范围(太小同理);

  • 缺乏操做符数值(输入-o,后方没有带数值,如arg6_1与arg6_2)时,提醒缺乏操做符数值,并告知-o范围。

  • 选择乘除法可是上界小于下界的平方,没法生成含有乘除的式子(如arg7)时,提醒上界需大于下界的平方;

  • 选择括号可是操做符默认为1或选择为1,不符合生成括号的条件(如arg7_1)时,提醒选择括号须要操做符数大于1。

  • –b(或-c)后带数字(如arg8与arg8_1),提醒-b(或-c)后不能带数字;

  • 出现除m、n、o、b、c外的字符如d等(如arg8_2),提醒输入值非法。

 

 


 

界面模块的详细设计过程

    设计图以下:

    咱们先从选择出题或作题开始。

    选择出题则进入出题参数输入界面。

    利用MouseListenermouseEntered(MouseEvent e)setTitle(String);使得鼠标移到参数上,标题会有提示功能。

    输入完毕点击确认后,由输入的参数判断是否有异常并提示直至无异常建立文件。

 1 public class submitListener implements ActionListener {  2 public void actionPerformed(ActionEvent e) {  3 String m = "题数与数值上下限为必填项,请按标题提示输入正整数!";  4 String m2 = "建立文件成功!";  5 int n0, lower0, upper0, o0, c0, b0;  6 o0 = 1;  7 c0 = 0;  8 b0 = 0;  9 String o1 = ""; 10 try { 11 n0 = Integer.parseInt(n.getText()); 12 lower0 = Integer.parseInt(lower.getText()); 13 upper0 = Integer.parseInt(upper.getText()); 14 if (n0 < 1 || n0 > 10000) { 15 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "题数范围为1-10000", "提示", 16  JOptionPane.INFORMATION_MESSAGE); 17 return; 18  } 19 if (lower0 < 1 || lower0 > 100) { 20 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "下界范围为1-100", "提示", 21  JOptionPane.INFORMATION_MESSAGE); 22 return; 23  } 24 if (upper0 < 50 || upper0 > 1000) { 25 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "上界范围为50-1000", "提示", 26  JOptionPane.INFORMATION_MESSAGE); 27 return; 28  } 29 if (upper0 < (2 * lower0)) { 30 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "上界必须大于两倍下界", "提示", 31  JOptionPane.INFORMATION_MESSAGE); 32 return; 33  } 34 } catch (NumberFormatException e2) { 35 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), m, "提示", JOptionPane.INFORMATION_MESSAGE); 36 return; 37  } 38 try { 39 o1 = o.getText(); 40 o0 = Integer.parseInt(o1); 41 } catch (NumberFormatException e2) { 42 if (!o1.equals("")) { 43 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "请输入1-10的正整数或不输入保持默认,默认为1", "提示", 44  JOptionPane.INFORMATION_MESSAGE); 45 return; 46  } 47  } 48 if (c.isSelected()) { 49 c0 = 1; 50  } 51 if (b.isSelected()) { 52 b0 = 1; 53  } 54 if (o0 == 1 && b0 == 1) { 55 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "括号须要操做符数量大于1", "提示", 56  JOptionPane.INFORMATION_MESSAGE); 57 return; 58  } 59 if (c0 == 1 && upper0 < (lower0 * lower0)) { 60 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "乘除法须要上界数值大于下界的平方", "提示", 61  JOptionPane.INFORMATION_MESSAGE); 62 return; 63  } 64  createFile.fileCreate(n0, lower0, upper0, o0, c0, b0); 65 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), m2, "提示", JOptionPane.INFORMATION_MESSAGE); 66 System.exit(0); 67  } 68 }
参数确认

    选择作题则先输入作题人名字(在这里建议使用英文,中文名字没法很好的记录)。

    接着上传文件,在这里使用了txt文件过滤器,使之仅可上传txt文件。

1 FileFilter filter = new FileNameExtensionFilter("Text file", "txt"); 2 JFileChooser fileChooser = new JFileChooser(); 3 fileChooser.setAcceptAllFileFilterUsed(false); 4 fileChooser.addChoosableFileFilter(filter); 5 FileSystemView fsv = FileSystemView.getFileSystemView();
过滤器

    另外,出题与作题都统一为utf-8编码,免去执行文件编码错误。

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true), "UTF-8"));
InputStreamReader read = new InputStreamReader(new FileInputStream(file), "utf-8");

    上传成功后开始计时作题,并于最后结果中显示用时。

    通过后面JTextPane控件的启发,我考虑到出题时题目长度有长短,为了更加美观显示,应该须要自动换行,我一样采用了HTML编辑文本的想法,作出改进。

 1 public static void JlabelSetText(JLabel jLabel, String longString) throws InterruptedException {  2 StringBuilder builder = new StringBuilder("<html>");  3 char[] chars = longString.toCharArray();  4 FontMetrics fontMetrics = jLabel.getFontMetrics(jLabel.getFont());  5 int start = 0;  6 int len = 0;  7 while (start + len < longString.length()) {  8 while (true) {  9 len++; 10 if (start + len > longString.length()) 11 break; 12 if (fontMetrics.charsWidth(chars, start, len) > jLabel.getWidth()) { 13 break; 14  } 15  } 16 builder.append(chars, start, len - 1).append("<br/>"); 17 start = start + len - 1; 18 len = 0; 19  } 20 builder.append(chars, start, longString.length() - start); 21 builder.append("</html>"); 22  jLabel.setText(builder.toString()); 23 }
换行

    计时方面我本来采用秒数计时,后来考虑到当作题时间较长时,秒数很难清晰明确的表达,因此改用了 hh:mm:ss 法显示。

 1 public static String getTimeStrBySecond(long second) {  2 if (second <= 0) {  3 return "00:00:00";  4  }  5 int hours = (int) second / HOUR_SECOND;  6 if (hours > 0) {  7  8 second -= hours * HOUR_SECOND;  9  } 10 int minutes = (int) second / MINUTE_SECOND; 11 if (minutes > 0) { 12 second -= minutes * MINUTE_SECOND; 13  } 14 return (hours > 10 ? (hours + "") 15 : ("0" + hours) + ":" + (minutes > 10 ? (minutes + "") : ("0" + minutes)) + ":" 16 + (second > 10 ? (second + "") : ("0" + second))); 17 }
秒数转换

    自动换行处理与秒数转换被我写入新类——dataDeal类中。

    最终作完题目后除了显示用时,还显示题数、分数、错题以及该题正确答案,非首次用户会显示历史分数以及最高分数。

    本来该部分使用了JTextArea控件,但学姐建议正确答案部分对齐显示会更加美观,并提出了C#中的ListView控件,但很遗憾,Java中彷佛并无。JTextArea控件是纯文本显示,很难作到不一样的对齐方式,因此我删除了该类。通过多方学习比较,我最终选择了JTextPane控件,该控件简单易用,可将文本显示为HTML文本,大大提升了编辑的样式性。我最终采起了表格法对齐,另外对重点突出的地方加粗变红显示,达到强调与必定视觉冲击效果,可从后文看到对比图。

 1 String text = "<p style='font-family:楷体; font-size:19'>" + name + " 本次用时<span style='color:red'><strong> "  2 + dataDeal.getTimeStrBySecond(spentTime) + " </strong></span>,得分<span style='color:red'><strong> "  3 + goal + " </strong></span>分。<br>";  4 if (size0 == 0) {  5 text += "你总共答了<span style='color:red'><strong> " + size  6 + " </strong></span>道题,并所有答对!<span style='color:red'><strong>恭喜!</strong></span></p>";  7 } else {  8 text += "你总共答了<span style='color:red'><strong> " + size  9 + " </strong></span>道题,答对<span style='color:red'><strong> " + size1 10 + " </strong></span>道,答错<span style='color:red'><strong> " + size0 11 + " </strong></span>道,分别为:</p><p><table border=0>"; 12 for (int i = 0; i < (size0 * 2); i++) { 13 text += "<tr><td style='font-family:楷体; font-size:19'><strong>" + wrong.get(i++) 14 + " </strong></td><td width='180' style='font-family:楷体; font-size:19;color:red'><strong> " 15 + wrong.get(i) + "</strong></td></tr>"; 16  } 17  } 18 text += "</table></p>"; 19 text += "<p style='font-family:楷体; font-size:19'>" + createFile.record(name, goal) + "</p>"; 20 21 JTextPane textarea = new JTextPane(); 22 textarea.setContentType("text/html"); 23  textarea.setText(text); 24 textarea.setEditable(false); 25 JScrollPane textAreascrollPane = new JScrollPane(textarea); 26 add(textAreascrollPane, BorderLayout.CENTER);
JTextPane

 


 

界面模块与计算模块的对接

    如图所示

    在界面模块选择出题输入参数以后调用fileCreate类,再由fileCreate类调用计算模块,建立result.txt

    在界面模块选择作题输入名字、上传文件、作题。作题时调用计算模块的stack类计算判断正确性,记录错题。最终结果由计算模块中的fileCreate类的record(String name, int goal)记录,由界面模块显示。

    实现的功能大体有12个,而且为了提升用户体验,修改了图标并增长了背景,将操做符数修改成下拉框选择,默认选择为1,避免输入非数字错误:

模式选择

出题参数输入(先后对比图)

出题参数要求提醒

输入参数有误提醒(见第七点异常)

生成文件

记录用户

上传文件(只容许txt文件)

判断文件是否为空或非练习题

计时

一道一道作题而且题目过长时自动换行

评分

    根据学姐给的建议作出了修改,如下为先后对比图,正确答案对齐,使之更加美观。另外我修改了作题时间的显示形式,这样当作题时间较长时能够更加清晰的看出时间状况。而作题时间、得分状况、错题与正确答案皆加粗甚至标红,使之更加显眼,提升用户体验。

记录历史分数与最高分数

 


 

结对编程

    咱们先一块儿分析了需求与功能的实现,并提出了一些有实质性的方法,并确认数据的传递方式。再分析各自的我的项目代码,指出了双方优劣性,在综合考虑选择基础代码加以改进。

    咱们根据本身较为擅长的方面分工,如相对之下,我对gui较为熟悉,而她对字符串处理较为熟悉,则我负责界面展现而她负责命令行的分析。各自写完以后咱们再复审双方代码,对代码不理解之处询问并补充注释,以及对双方异常状况补充。最后在一块儿整合双方代码,使之成为完整项目。

 


 

结对编程的优缺点

    在此过程当中咱们互相帮助、互相学习、能力上获得互补,而代码和产品质量提升,有效地减小bug而且考虑到更多方面的状况。有两台电脑能够测试程序效果,如她的电脑比我小,个人gui显示不一样,她的部分算式被遮挡,最终我选择了将按钮部分的面板设为透明,解决了这个问题。

    不足之处在于队友之间的进度相互影响,不一样的代码风格之间的磨合也花费了必定时间。

    双方优缺点:

  庄莉 王璐瑶
优势

认真细心,有责任心

不辞辛苦

代码能力高

对字符串以及字符串数组的处理十分熟练

动手能力强

颇有想法,有好点子

缺点

有时候对于小问题过于钻牛角尖

因生病而不在状态,没注意到比较细的地方,时间较少

 


 

实际PSP

PSP

任务内容

实际完成须要的时间(min)

Planning

计划

0.5

Estimate

   估计这个任务须要多少时间,并规划大体工做步骤

0.5

Development

开发

53.25

   Analysis

需求分析 (包括学习新技术)

0.5

Design Spec

  生成设计文档

0.25

  Design Review

设计复审 (和同事审核设计文档)

0.25

Coding Standard

 代码规范 (为目前的开发制定合适的规范)

0.25

 Design

 具体设计

1

Coding

具体编码

40

Code Review

 代码复审

1

Test

测试(自我测试,修改代码,提交修改)

10

Reporting

报告

9

Test Report

测试报告

8

 Size Measurement

计算工做量

0.5

Postmortem & Process Improvement Plan

过后总结, 并提出过程改进计划

0.5

 


 

    本次结对编程真的让我学到不少知识,尤为是各类操做,就像上一篇博客的连接同样,我查了许许多多这样的连接,学习了一种有一种的方法,与队友配合,完成了此次项目。而每次写博客,都能从新总结个人思路,受益良多。

    虽然真的很辛苦,但能作出来也就够了。

 


 

    如下部分因为时间与精力关系,咱们小组并无完成,仅提供思路参考,有想法的同窗可加以尝试。

    附加题多语言思路参考:程序国际化

 

https://blog.csdn.net/zhuxinquan61/article/details/51540806

 

http://www.javashuo.com/article/p-gdfjqelb-me.html

 

    思路注意点参考:

  • 文字描述使用短语、名词与阿拉伯数字,便于翻译。 标准语言建议英语,中文字符难以使用字符串判断内容。
  • 语言选择可为下拉框列表旁边带一不可编辑的文本框。因为能够自添加,因此能够创建一个文件(如txt),文件中加入选项,执行代码时读出文件,for循环将每一项添加进下拉框列表中。有一项设置为其余或自定义,选择它时,旁边的文本框变为可编辑,用于添加语言(也可以让下拉框为可编辑,当输入的语言下拉选项中没有时认为添加新语言)。
  • 添加语言则需配置文件(参考网址),将全部须要翻译的文字让用户对应翻译。生成新的配置文件,并命名为该语言(使用英文命名),将该语言添加到保存下拉框选项的文件中。
  • 当用户选择一种语言时,经过其相同的命名,便可调用该语言的配置文件进行翻译,达到多语言转化功能。
相关文章
相关标签/搜索