四则运算结对项目之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 ...
随机推荐
- Java基础——常用类之日期时间类
如果有机会,请尝试Java8中全新的时间日期API!(参见Java8新特性随笔) 如果还是使用Java7及之前的版本,那么你可以尝试一些工具类(参考使用工具类相关的Hutool-DateUtil) 如 ...
- flex 自定义组件的编写
使用flex也很久了,也改过别人写的flex自定义组件,但是就是没有系统的研究下flex组件的编写步骤,和要注意的东西,在这里我参照一本书中的例子,好好的理解下,也为了巩固下自己对flex的理解! 1 ...
- PPAS的MTK tool 工具使用说明
磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面: PostgreSQL基础知识与基本操作索引页 回到顶级页面:PostgreSQL索引页 [作者 高健@博客园 luckyjackg ...
- 仙人掌&圆方树
仙人掌&圆方树 Tags:图论 [x] [luogu4320]道路相遇 https://www.luogu.org/problemnew/show/P4320 [ ] [SDOI2018]战略 ...
- [FJOI2015]火星商店问题
[FJOI2015]火星商店问题 神仙线段树分治...不过我不会. 这题用线段树套可持久化Trie还是能写的. 常数有点大,洛谷垫底水平. // luogu-judger-enable-o2 #inc ...
- 开源项目CIIP(企业信息管理系统框架).2018.1.0910版更新介绍-上周工作总结
又狂撸了一周的代码.简化了0904版本的多数操作. 上一次更新时,总共需要10步,这次简化成3步.嗯嗯,自我感觉不错. 重要的:在创建项目时,可以选择常用模块啦! 第一步:启动CIIP.Designe ...
- IIS7 增加JSON文件解析
在MIME增加一个Json类型,在MIME增加一个配置如:添加---> 文件扩展名为 .JSON ,MIME类型为text/json(也有将application/x-javascript) 然 ...
- 第一次玩github,第一个开源小项目——xxoo
引言 由于最近的工作写代码比较少,这让LZ产生了一丝危机感.于是便想找一个办法可以没事自己写写代码,自然而然就想到了github.接下来便是一阵捣鼓的过程,其实整个过程很快,主要过程就是注册一个账号, ...
- 相机标定与矫正opencv+MATLAB
博客转载自:http://blog.csdn.net/Loser__Wang/article/details/51811347 本文目的在于记录如何使用MATLAB做摄像机标定,并通过opencv进行 ...
- 最安全的聊天工具——Cryptocat
关于Cryptocat Cryptocat 是啥?Cryptocat,俗称 "加密猫",是一款非常注重安全的聊天软件. 美国前中情局员工斯诺登在躲避美国政府追捕过程中,就是使用 C ...