四则运算结对项目之GUI
本次结对编程让我学到了许多许多知识,受益匪浅!在此之前,我没想过我能做出一个双击运行的小程序。
感谢我的队友与我同心协力,感谢室友宇欣告诉我操作符为“最多多少”而不是“多少”并教我使用效能分析工具,感谢陈杰不辞辛苦帮我测试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的更多相关文章
- 小学四则运算结对项目报告(GUI)
小学四则运算结对项目报告(GUI) 一.Coding.Net项目地址: https://git.coding.net/wsshr/Calculation.git 二.PSP表格(完成前): PSP 任 ...
- 小学四则运算结对项目报告【GUI】
写在前面 这次的结对项目我做了很长时间,感触也很多.在这次项目中我使用了Java GUI作为和用户的交互方式,但是在上Java课的时候我对GUI和事件驱动这里并没有学的多好,可能是当时对编程还没有什么 ...
- 四则运算结对编程(GUI)
四则运算GUI coding地址:https://git.dev.tencent.com/qyj814/GUI.git 结对伙伴:李梦宇 一.题目要求 定制出题要求.每次出题时用户都可以在界面上定制如 ...
- 结对项目作业GUI
一.Coding.Net项目地址:https://git.coding.net/zhengsh589/CoupleProject.git 二.PSP表格(完成前): PSP 任务内容 计划共完成需要的 ...
- 高级软件工程2017第3次作业——结对项目:四则运算题目生成程序(基于GUI)
Deadline:2017-10-11(周三)21:00pm (注:以下内容参考集大作业 ) 前言 想过和别人一起探索世界吗?多么希望,遇到困难时,有人能一起探讨:想要懈怠时,有人推你一把:当你专注于 ...
- 结对项目——四则运算GUI项目
一.项目地址:https://git.coding.net/lvgx/wsz.git 二.PSP: PSP2.1 任务内容 计划共完成需要的时间(min) 实际完成需要的时间(min) Plannin ...
- 结对项目-四则运算出题程序(GUI版)
目录: 一.致搭档(含项目地址) 二.PSP(planning) 三.结对编程中对接口的设计 四.计算模块接口的设计与实现过程 五.计算模块接口部分的性能改进 六.计算模块部分单元测试展示 七.计算模 ...
- 结对项目-小学生四则运算系统(GUI)
Coding克隆地址:https://git.coding.net/FrrLolix/CalGUI.git 伙伴博客:http://www.cnblogs.com/wangyy39/p/8763244 ...
- 结对项目:四则运算题目生成器(Java)
目录 一.需求分析 二.开发计划 三.实现方案 3.1 项目结构 3.2 代码说明 3.2.1 出题功能代码 3.2.3 批卷功能代码 3.2.3 四则运算功能代码 四.效能分析 4.1 程序效能 4 ...
随机推荐
- 在centos6.5下用nginx无法连接zabbix与mysql的解决办法
一般情况下默认的webserver是apache.zabbix也不例外,官方文档全都是推荐用apache. 如果执意用nginx来做webserver的话,php引导需要再安装一个php-fpm.而且 ...
- Web安全0003 - MySQL SQL注入 - union查询核心语法
注:本文是学习网易Web安全进阶课的笔记,特此声明. 查库,select schema_name from information_schema.schemata; 查表,select table_n ...
- Dotnet Core Cli 解决方案中多个项目的相互引用和第三方库引用
dotnet add app/app.csproj reference lib/lib.csproj app项目引用lib项目 dotnet add package Newtonsoft.Json 当 ...
- BZOJ4145_The Prices_KEY
题目传送门 看到M<=16经典状态压缩的数据范围,考虑题目. 一道类似于背包的题目. 设f[i][j]表示前i个商店,物品购买状态为j. 先将f[i][j]加上w[i](到i的路费),转移一次, ...
- 控制 matplotlib 子图大小
效果图: 代码: import numpy as np import matplotlib.pyplot as plt '''调整 matplotlib 子图的大小''' x1 = np.linspa ...
- Gitlab+Jenkins学习之路(九)之Jenkins的远程管理和集群
一.Jenkins的远程管理 Jenkins的远程管理方式包含: Shell ssh SSH Plugin ansible.saltstack (1)Shell ssh在项目构建时,jenkins使用 ...
- [COCI2009]Dvapravca 计算几何
[COCI2009]Dvapravca LG传送门 先给出考场上的\(O(n^3)\)乱搞方法:枚举一个蓝点和一个红点,找出过着两个点的直线,再枚举蓝点找出这条直线最多能往两边扩展多宽,最后枚举红点计 ...
- Restful和WeBAPI学习笔记
1.restful是基于无状态的,所谓无状态就是说客户端和服务端的每次通话都是独立的,不存在session和cookie之类的保存状态的机制,基于该协议可实现简单的curd操作, 其操作分为get\p ...
- Tomcat学习(一)------部署Web应用方法总结
Tomcat部署Web应用方法总结 在Tomcat中部署Java Web应用程序有两种方式:静态部署和动态部署. 在下文中$CATALINA_HOME指的是Tomcat根目录. 一.静态部署 静态部署 ...
- 【日常训练】Hockey(CodeForces-96C)
题意与分析 对于这题题意的理解比较重要,因为这是一条傻逼题: 大小写保持不变 原串中出现的非法字符串里的每一个字符都要替换 Lucky Letter越多越好 这样一种情况下,算法其实特别简单.我傻逼在 ...