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

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

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

本人:庄莉,学号:2016012034

队友:王璐瑶,学号:2016012095


计划PSP

PSP

任务内容

计划共完成需要的时间(h)

Planning

计划

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)不再使用,改用了栈运算。

     // 计算结果
public static Object result(String temp) {
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine se = sem.getEngineByName("js");
Object last = 0;
try {
last = se.eval(temp);
} catch (ScriptException e) {
e.printStackTrace();
}
return last;
}

result函数

在栈的运算中加入判断

 if (Math.abs(sresulat) > upper || Math.abs(sresulat) < lower)
{
return 0;
}

判断

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

另外,原本的操作符是一开始随机生成好的再判断选择后一个数,然后再判断符号是否合法,再修改符号,如果还是有小数或负数,则重新运行生成算式的函数,这样使得代码运行有些慢且多次运行。再加上数值范围的限定以及可以存在负数,我改变了想法。

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

 // 相加不超过范围
public static int decide0(int x, int min, int max)
{
int y;
int temp = 0;
if (x > 0)
{
temp = max - min - x + 1;// 加一个正整数范围
} else
{
temp = max - (min - x) + 1;// 加至正整数的范围
}
if (temp < 0)
{// 范围小于0
if (x > 0)
{
temp = Math.abs(x) - min * 2 + 1;// 正整数过大,需加负数
y = 0 - (int) (Math.random() * temp) - min;
} else
{
temp = Math.abs(x) - 2 * min + 1;// 负数过小,越值,加小整数至负数范围
y = (int) (Math.random() * temp) + min;
}
} else
{
y = (int) (Math.random() * temp + min);
}
return y;
} // 相减不小于最小
public static int decide1(int x, int min, int max)
{
int temp = 0;
int y = 0;
if (x > 0)
{
temp = x - 2 * (min - 1) - 1; // 减一个正数范围
} else
{
temp = max + x - min + 1;// 减一个正数范围
}
if (temp > 0)
{
if (x < 0 && temp < min)
{
temp = Math.abs(x) - 2 * min + 1;// 负数过小,需减负数
y = 0 - (int) (Math.random() * temp) - min;
} else
{
y = (int) (Math.random() * temp + min);
}
} else
{
temp = max - x - min + 1;// 只有x>0的情况会出现,正数过小,需减负数
y = 0 - (int) (Math.random() * temp) - min;
}
return y;
}

加减法的后一位数选定

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

 // 操作符的选定
public static int operator(int num, int middle2, int middle3)
{
if (Math.abs(num) <= middle2)
{// 除法下界
if (Math.abs(num) < middle3)
{
return 3;
} else
{
return 0;
}
} else if (Math.abs(num) >= middle3)
{// 乘法上界
return 2;
} else
{
return (int) (Math.random() * 4);
}
}
// 下一位数字的选定
public static int[] numberB(int key, int num, int lower, int upper)
{
int[] find = new int[] { 0, lower };
if (key == 0)
{
find[1] = decide0(num, lower, upper);
return find;
} else if (key == 2)
{
int[] judge = new int[2];
judge = decide2(num, lower);// 确保能够整除,并不低于下限
if (judge[0] == 0)
{
find[1] = judge[1];
return find;
} else
{
find[0] = 1;
}
} else if (key == 3)
{
find[1] = decide3(num, lower, upper);
if (find[0] == 0)
{
return find; // 乘法不超过上限
}
}
find[1] = decide1(num, lower, upper);
return find;
}

操作符选定以及下一位数字的选定

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

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

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

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

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

 // 带括号的四则运算
public static String Bracket(int lower, int upper, int o) {
int middle2 = lower * lower;// 除法下界
int middle3 = upper / lower;// 乘法上界
int brack_left = 0; // 记录未匹配的左括号个数
int brack = 0; // 括号个数
int j = 0;
char[] p = new char[] { '+', '-', '÷', '*' };
String temp1 = "";
int[] num = new int[o + 1]; // 数字
int[] key = new int[o]; // 符号所在的下标
num[0] = (int) (Math.random() * (upper - lower + 1) + lower);
int result;
int[] find = new int[2];
for (j = 0; j < (o - 1); j++) {
if (num[j] < 0) {
temp1 += "(" + String.valueOf(num[j]) + ")";
} else {
temp1 += String.valueOf(num[j]);
}
int tmpcnt = brack_left;
for (int i = 0; i < tmpcnt; i++) { // 若当前有未匹配的左括号,则对每一个未匹配的左括号,都有一定概率生成相应右括号。
if ((int) (Math.random() * 5) > 1) { // 生成右括号概率为0.6
brack_left--;
temp1 += ")";
}
}
key[j] = calculate.operator(num[j], middle2, middle3);
find = calculate.numberB(key[j], num[j], lower, upper);
if (find[0] == 1) {
key[j] = 1;
}
num[j + 1] = find[1];
temp1 += String.valueOf(p[key[j]]);
if (((brack * 2) <= o) && (((int) (Math.random() * 2)) == 0)) { // 以一定概率生成左括号,概率为1/2
temp1 += "(";
brack++;
brack_left++;
j++;
if (num[j] < 0) {
temp1 += "(" + String.valueOf(num[j]) + ")";
} else {
temp1 += String.valueOf(num[j]);
} // 生成左括号后必须生成一个数字和运算符,不然可能出现(15)这样的错误
key[j] = calculate.operator(num[j], middle2, middle3);
find = calculate.numberB(key[j], num[j], lower, upper);
if (find[0] == 1) {
key[j] = 1;
}
num[j + 1] = find[1];
temp1 += p[key[j]];
}
}
while (j != o) { // 判断是否为最后一个数
if (num[j] < 0) {
temp1 += "(" + String.valueOf(num[j]) + ")";
} else {
temp1 += String.valueOf(num[j]);
}
key[j] = calculate.operator(num[j], middle2, middle3);
temp1 += p[key[j]];
find = calculate.numberB(key[j], num[j], lower, upper);
if (find[0] == 1) {
key[j] = 1;
}
j++;
num[j] = find[1];
}
if (num[o] < 0) {
temp1 += "(" + String.valueOf(num[o]) + ")";
} else {
temp1 += String.valueOf(num[o]);
}
while ((brack_left) != 0) { // 补全右括号
temp1 += ")";
brack_left--;
}
result = stack.work(temp1, lower, upper, 1);
if (result == 0) {
temp1 = Bracket(lower, upper, o);
}
return temp1; } }

有括号四则运算

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

性能分析过程截图:

按F4,出现以下截图。资源全部被回收。证明没有资源泄露。程序性能良好。

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

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


单元测试

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

栈的测试

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

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

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

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

 @Test
public void testAll() {
// 顺序不同以及异常测试。生成的文件会被覆盖。
String[] arg0 = new String[] { "-n", "100", "-m", "5", "100", "-o", "3", "-c", "-b" };
String[] arg1 = new String[] { "-m", "5", "50", "-o", "3", "-n", "100", "-c" };
String[] arg2 = new String[] { "-o", "3", "-m", "5", "50", "-n", "100", "-b" };
String[] arg3 = new String[] { "-n", "100", "-o", "3", "-m", "5", "50" };
Command.main(arg0);// 有括号四则运算测试
Command.main(arg1);// 四则运算测试
Command.main(arg2);// 有括号加减运算测试
Command.main(arg3);// 加减运算测试
}

命令行正确输入测试

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

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

 @Test
public void testDecide2() {
int[] find = new int[2];
find = calculate.decide2(20, 2);
assertEquals(2, find[1]);
find = calculate.decide2(13, 2);
assertEquals(1, find[0]);
}

除法选择除数测试

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

 // 被除数能被除数整除并不低于最小
public static int[] decide2(int x, int min)
{
int[] judge = new int[] { 1, 0 };
int temp = Math.abs(x) / min - min + 1;// 除数的范围
for (int i = min; i < (temp + min); i++)
{
if (Math.abs(x) % i == 0)
{// 判断是否整除
judge[0] = 0;
judge[1] = i;
return judge;
}
}
return judge;
}

decide2函数

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


异常说明

 @Test
public void testAll() {
String[] arg4 = new String[] { "-o", "3", "-m", "5", "50", "-n" };
String[] arg4_1 = new String[] { "-o", "3", "-n", "-m", "5", "50" };
String[] arg4_2 = new String[] { "-n", "100000", "-m", "5", "50" };
String[] arg4_3 = new String[] { "-o", "3", "-m", "5", "50" }; String[] arg5 = new String[] { "-n", "50" };
String[] arg5_1 = new String[] { "-m", "5", "-n", "50", "-o", "3" };
String[] arg5_2 = new String[] { "-n", "50", "-m", "3" };
String[] arg5_3 = new String[] { "-n", "50", "-o", "3", "-m" };
String[] arg5_4 = new String[] { "-m", "-n", "50" }; String[] arg6 = new String[] { "-o", "11", "-m", "5", "50", "-n", "100" };
String[] arg6_1 = new String[] { "-n", "100", "-o", "-m", "5", "50" };
String[] arg6_2 = new String[] { "-n", "100", "-m", "5", "50", "-o" }; String[] arg7 = new String[] { "-m", "5", "20", "-n", "100", "-c" };
String[] arg7_1 = new String[] { "-m", "5", "50", "-n", "100", "-b" }; String[] arg8 = new String[] { "-b", "1", "-o", "3", "-m", "5", "50", "-n", "100" };
String[] arg8_1 = new String[] { "-c", "1", "-o", "3", "-m", "5", "50", "-n", "100" };
String[] arg8_2 = new String[] { "-n", "100", "-m", "5", "50", "-d" }; Command.main(arg4);// 缺少题数值测试
Command.main(arg4_1);
Command.main(arg4_2);// 题数值过大测试
Command.main(arg4_3);// 缺少题数测试 Command.main(arg5);// 缺少数值范围
Command.main(arg5_1);// 缺少数值范围上限测试
Command.main(arg5_2);
Command.main(arg5_3);// 缺少数值范围上下限测试
Command.main(arg5_4); Command.main(arg6);// 操作符数值过大测试
Command.main(arg6_1);// 缺少操作符数值测试
Command.main(arg6_2); Command.main(arg7);// 乘除需要上界大于下界的平方
Command.main(arg7_1);// 括号需要操作符数大于1 Command.main(arg8);// 输入非法测试之b后有数字
Command.main(arg8_1);// 输入非法测试之c后有数字
Command.main(arg8_2);// 输入非法测试之无辨识字符
}

命令行异常输入测试

对于命令行可能出现的异常大概有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),提醒输入值非法。


界面模块的详细设计过程

设计图如下:

我们先从选择出题或做题开始。

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

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

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

 public class submitListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String m = "题数与数值上下限为必填项,请按标题提示输入正整数!";
String m2 = "创建文件成功!";
int n0, lower0, upper0, o0, c0, b0;
o0 = 1;
c0 = 0;
b0 = 0;
String o1 = "";
try {
n0 = Integer.parseInt(n.getText());
lower0 = Integer.parseInt(lower.getText());
upper0 = Integer.parseInt(upper.getText());
if (n0 < 1 || n0 > 10000) {
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "题数范围为1-10000", "提示",
JOptionPane.INFORMATION_MESSAGE);
return;
}
if (lower0 < 1 || lower0 > 100) {
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "下界范围为1-100", "提示",
JOptionPane.INFORMATION_MESSAGE);
return;
}
if (upper0 < 50 || upper0 > 1000) {
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "上界范围为50-1000", "提示",
JOptionPane.INFORMATION_MESSAGE);
return;
}
if (upper0 < (2 * lower0)) {
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "上界必须大于两倍下界", "提示",
JOptionPane.INFORMATION_MESSAGE);
return;
}
} catch (NumberFormatException e2) {
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), m, "提示", JOptionPane.INFORMATION_MESSAGE);
return;
}
try {
o1 = o.getText();
o0 = Integer.parseInt(o1);
} catch (NumberFormatException e2) {
if (!o1.equals("")) {
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "请输入1-10的正整数或不输入保持默认,默认为1", "提示",
JOptionPane.INFORMATION_MESSAGE);
return;
}
}
if (c.isSelected()) {
c0 = 1;
}
if (b.isSelected()) {
b0 = 1;
}
if (o0 == 1 && b0 == 1) {
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "括号需要操作符数量大于1", "提示",
JOptionPane.INFORMATION_MESSAGE);
return;
}
if (c0 == 1 && upper0 < (lower0 * lower0)) {
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "乘除法需要上界数值大于下界的平方", "提示",
JOptionPane.INFORMATION_MESSAGE);
return;
}
createFile.fileCreate(n0, lower0, upper0, o0, c0, b0);
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), m2, "提示", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}

参数确认

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

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

 FileFilter filter = new FileNameExtensionFilter("Text file", "txt");
JFileChooser fileChooser = new JFileChooser();
fileChooser.setAcceptAllFileFilterUsed(false);
fileChooser.addChoosableFileFilter(filter);
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编辑文本的想法,做出改进。

 public static void JlabelSetText(JLabel jLabel, String longString) throws InterruptedException {
StringBuilder builder = new StringBuilder("<html>");
char[] chars = longString.toCharArray();
FontMetrics fontMetrics = jLabel.getFontMetrics(jLabel.getFont());
int start = 0;
int len = 0;
while (start + len < longString.length()) {
while (true) {
len++;
if (start + len > longString.length())
break;
if (fontMetrics.charsWidth(chars, start, len) > jLabel.getWidth()) {
break;
}
}
builder.append(chars, start, len - 1).append("<br/>");
start = start + len - 1;
len = 0;
}
builder.append(chars, start, longString.length() - start);
builder.append("</html>");
jLabel.setText(builder.toString());
}

换行

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

 public static String getTimeStrBySecond(long second) {
if (second <= 0) {
return "00:00:00";
}
int hours = (int) second / HOUR_SECOND;
if (hours > 0) { second -= hours * HOUR_SECOND;
}
int minutes = (int) second / MINUTE_SECOND;
if (minutes > 0) {
second -= minutes * MINUTE_SECOND;
}
return (hours > 10 ? (hours + "")
: ("0" + hours) + ":" + (minutes > 10 ? (minutes + "") : ("0" + minutes)) + ":"
+ (second > 10 ? (second + "") : ("0" + second)));
}

秒数转换

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

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

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

 String text = "<p style='font-family:楷体; font-size:19'>" + name + " 本次用时<span style='color:red'><strong> "
+ dataDeal.getTimeStrBySecond(spentTime) + " </strong></span>,得分<span style='color:red'><strong> "
+ goal + " </strong></span>分。<br>";
if (size0 == 0) {
text += "你总共答了<span style='color:red'><strong> " + size
+ " </strong></span>道题,并全部答对!<span style='color:red'><strong>恭喜!</strong></span></p>";
} else {
text += "你总共答了<span style='color:red'><strong> " + size
+ " </strong></span>道题,答对<span style='color:red'><strong> " + size1
+ " </strong></span>道,答错<span style='color:red'><strong> " + size0
+ " </strong></span>道,分别为:</p><p><table border=0>";
for (int i = 0; i < (size0 * 2); i++) {
text += "<tr><td style='font-family:楷体; font-size:19'><strong>" + wrong.get(i++)
+ " </strong></td><td width='180' style='font-family:楷体; font-size:19;color:red'><strong> "
+ wrong.get(i) + "</strong></td></tr>";
}
}
text += "</table></p>";
text += "<p style='font-family:楷体; font-size:19'>" + createFile.record(name, goal) + "</p>"; JTextPane textarea = new JTextPane();
textarea.setContentType("text/html");
textarea.setText(text);
textarea.setEditable(false);
JScrollPane textAreascrollPane = new JScrollPane(textarea);
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

https://blog.csdn.net/zhoudaxia/article/details/37536195

思路注意点参考:

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

四则运算结对项目之GUI的更多相关文章

  1. 小学四则运算结对项目报告(GUI)

    小学四则运算结对项目报告(GUI) 一.Coding.Net项目地址: https://git.coding.net/wsshr/Calculation.git 二.PSP表格(完成前): PSP 任 ...

  2. 小学四则运算结对项目报告【GUI】

    写在前面 这次的结对项目我做了很长时间,感触也很多.在这次项目中我使用了Java GUI作为和用户的交互方式,但是在上Java课的时候我对GUI和事件驱动这里并没有学的多好,可能是当时对编程还没有什么 ...

  3. 四则运算结对编程(GUI)

    四则运算GUI coding地址:https://git.dev.tencent.com/qyj814/GUI.git 结对伙伴:李梦宇 一.题目要求 定制出题要求.每次出题时用户都可以在界面上定制如 ...

  4. 结对项目作业GUI

    一.Coding.Net项目地址:https://git.coding.net/zhengsh589/CoupleProject.git 二.PSP表格(完成前): PSP 任务内容 计划共完成需要的 ...

  5. 高级软件工程2017第3次作业——结对项目:四则运算题目生成程序(基于GUI)

    Deadline:2017-10-11(周三)21:00pm (注:以下内容参考集大作业 ) 前言 想过和别人一起探索世界吗?多么希望,遇到困难时,有人能一起探讨:想要懈怠时,有人推你一把:当你专注于 ...

  6. 结对项目——四则运算GUI项目

    一.项目地址:https://git.coding.net/lvgx/wsz.git 二.PSP: PSP2.1 任务内容 计划共完成需要的时间(min) 实际完成需要的时间(min) Plannin ...

  7. 结对项目-四则运算出题程序(GUI版)

    目录: 一.致搭档(含项目地址) 二.PSP(planning) 三.结对编程中对接口的设计 四.计算模块接口的设计与实现过程 五.计算模块接口部分的性能改进 六.计算模块部分单元测试展示 七.计算模 ...

  8. 结对项目-小学生四则运算系统(GUI)

    Coding克隆地址:https://git.coding.net/FrrLolix/CalGUI.git 伙伴博客:http://www.cnblogs.com/wangyy39/p/8763244 ...

  9. 结对项目:四则运算题目生成器(Java)

    目录 一.需求分析 二.开发计划 三.实现方案 3.1 项目结构 3.2 代码说明 3.2.1 出题功能代码 3.2.3 批卷功能代码 3.2.3 四则运算功能代码 四.效能分析 4.1 程序效能 4 ...

随机推荐

  1. 在centos6.5下用nginx无法连接zabbix与mysql的解决办法

    一般情况下默认的webserver是apache.zabbix也不例外,官方文档全都是推荐用apache. 如果执意用nginx来做webserver的话,php引导需要再安装一个php-fpm.而且 ...

  2. Web安全0003 - MySQL SQL注入 - union查询核心语法

    注:本文是学习网易Web安全进阶课的笔记,特此声明. 查库,select schema_name from information_schema.schemata; 查表,select table_n ...

  3. Dotnet Core Cli 解决方案中多个项目的相互引用和第三方库引用

    dotnet add app/app.csproj reference lib/lib.csproj app项目引用lib项目 dotnet add package Newtonsoft.Json 当 ...

  4. BZOJ4145_The Prices_KEY

    题目传送门 看到M<=16经典状态压缩的数据范围,考虑题目. 一道类似于背包的题目. 设f[i][j]表示前i个商店,物品购买状态为j. 先将f[i][j]加上w[i](到i的路费),转移一次, ...

  5. 控制 matplotlib 子图大小

    效果图: 代码: import numpy as np import matplotlib.pyplot as plt '''调整 matplotlib 子图的大小''' x1 = np.linspa ...

  6. Gitlab+Jenkins学习之路(九)之Jenkins的远程管理和集群

    一.Jenkins的远程管理 Jenkins的远程管理方式包含: Shell ssh SSH Plugin ansible.saltstack (1)Shell ssh在项目构建时,jenkins使用 ...

  7. [COCI2009]Dvapravca 计算几何

    [COCI2009]Dvapravca LG传送门 先给出考场上的\(O(n^3)\)乱搞方法:枚举一个蓝点和一个红点,找出过着两个点的直线,再枚举蓝点找出这条直线最多能往两边扩展多宽,最后枚举红点计 ...

  8. Restful和WeBAPI学习笔记

    1.restful是基于无状态的,所谓无状态就是说客户端和服务端的每次通话都是独立的,不存在session和cookie之类的保存状态的机制,基于该协议可实现简单的curd操作, 其操作分为get\p ...

  9. Tomcat学习(一)------部署Web应用方法总结

    Tomcat部署Web应用方法总结 在Tomcat中部署Java Web应用程序有两种方式:静态部署和动态部署. 在下文中$CATALINA_HOME指的是Tomcat根目录. 一.静态部署 静态部署 ...

  10. 【日常训练】Hockey(CodeForces-96C)

    题意与分析 对于这题题意的理解比较重要,因为这是一条傻逼题: 大小写保持不变 原串中出现的非法字符串里的每一个字符都要替换 Lucky Letter越多越好 这样一种情况下,算法其实特别简单.我傻逼在 ...