高级软件工程2017第3次作业
0.小组成员
2017282110284 章辉宇
2017282110242 张宇光
1.项目地址
GitHub:https://github.com/fz267671/ArithmeticOpProject
2.PSP
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) |
---|---|---|
Planning | 计划 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 20 |
Development | 开发 | 1225 |
· Analysis | · 需求分析 (包括学习新技术) | 120 |
· Design Spec | · 生成设计文档 | 40 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 40 |
· Design | · 具体设计 | 120 |
· Coding | · 具体编码 | 800 |
· Code Review | · 代码复审 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 45 |
Reporting | 报告 | 100 |
· Test Report | · 测试报告 | 50 |
· Size Measurement | · 计算工作量 | 30 |
·Postmortem& Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 |
合计 | 1375 |
3.解题思路
刚拿到题目时,则是运用第二次作业的成果,在此基础上做一个相应的界面即可,由于我们用过的语言是C和Java,所以我们选择了在VS上利用C#写相应的界面,完成题目的基本要求。对于题目中我们不熟悉的语言转换的问题,直接在网上百度相应的代码,稍加修改。网上前辈的方法也进行了相应的参考:http://www.cnblogs.com/1175429393wljblog/p/5267918.html 。
出现分歧时都会首先考虑到代码的实现难度以及用户在使用过程中的方便程度,进行相应的讨论,比如在进行多语言转换的过程中会存在界面的某些显示转换比较麻烦,界面看起来觉得会比较多余,没有什么必要的存在,我们最终选择删除,降低难度的同时也使界面看得更舒服。
4.设计过程
4.1 基本GUI实现
这一部分基本就是对作业二已经实现的功能用界面展示,其中添加了对用户输入合法性判断,提交时利用正则表达式对用户输入过滤,如果输入不是数字弹窗提示用户重新输入。
4.2 计时功能实现
当用户输入题目数量,点击开始自动开始计时,答题结束时停止计时。具体过程:首先,加入计时器timer,在窗体加载时初始化计时器,定义一个按秒变化的全局计时变量t,在开始事件中启动计时器;然后,新建一个时间函数将t转换成hh:mm:ss的格式;最后,在计时器触发事件中对t进行加一操作,获取t的时间格式并显示。
4.3 记录用户对错数量
这个部分用到文件的读写,窗体加载时从文件读取对错数量,窗体退出时将对错数量写入文件。
4.4 实现语言切换
一开始考虑在程序中为界面上的所有国家的文字信息,在代码中进行赋值,这样的做法是可以的,但绝对是愚蠢的,而且如果实现很多种不同语言的版本,那就需要大量重复的代码,并且维护起来也相当麻烦。看了几篇参考博客,试着用资源文件实现,根据题目需求为窗体创建三个对应相应语言的资源文件,然后在资源文件中添加不用语言版本的字符串资源,最后在菜单不用语言单机事件函数中添加代码实现更新窗口的语言信息。
5.代码说明
5.1 基本GUI
5.1.1 对输入作合法性判断
1 //获取用户输入 2 string userAns = textBox2.Text.ToString(); 3 //如果输入不是数字,要求重输 4 if (!isNumberic(userAns)) 5 { 6 MessageBox.Show(rm.GetString("message1"), rm.GetString("message2"), 7 MessageBoxButtons.OK, MessageBoxIcon.Error); 8 textBox2.Text = ""; 9 return; 10 } 11 12 /// <summary> 13 /// 通过正则表达式判断输入是否为数字 14 /// </summary> 15 protected bool isNumberic(string message) 16 { 17 System.Text.RegularExpressions.Regex rex = 18 new System.Text.RegularExpressions.Regex(@"^(-?[0-9]+[/]?[0-9]*)$"); 19 if (rex.IsMatch(message)) 20 { 21 return true; 22 } 23 else 24 return false; 25 }
5.1.2 点击开始按钮,产生一定数量的题目并开始计时
private void button1_Click(object sender, EventArgs e) { //计时器清零,并开始计时 t = 0; this.label10.Text = "00:00:00"; this.timer1.Enabled = true; button1.Enabled = false; button3.Enabled = true; button2.Enabled = false; //获取总题数 problem_Nums = int.Parse(textBox1.Text.ToString()); problem_Now = 1; score = 100; //初始化运算式 expression = ""; nums_wrong = 0; //计算四则运算式的正确结果 rightAns = new ExpressionHelper().getResOfPostfix(); //显示第一道题目 label5.Text = "题目" + problem_Now.ToString() + ":"; label8.Text = expression; }
5.1.3 点击提交按钮,计算正确答案并批改
private void button3_Click(object sender, EventArgs e) { //获取用户输入 string userAns = textBox2.Text.ToString(); //如果输入不是数字,要求重输 if (!isNumberic(userAns)) { MessageBox.Show(rm.GetString("message1"), rm.GetString("message2"), MessageBoxButtons.OK, MessageBoxIcon.Error); textBox2.Text = ""; return; } button3.Enabled = false; button4.Enabled = true; //如果已经是最后一题 if (problem_Now == problem_Nums) { button4.Enabled = false; button2.Enabled = true; } //判断对错,并改变对错题数量 if (userAns == rightAns){ label9.Text = rm.GetString("result1"); this.correct_Number++; //正确题数+1 label11.Text = correct_Number.ToString(); } else { label9.Text = rm.GetString("result2") + rightAns; this.wrong_Number++; //错误题数+1 label12.Text = wrong_Number.ToString(); //当前错题数+1 nums_wrong += 1; } }
5.1.4 结束答题,计算总得分
private void button2_Click(object sender, EventArgs e) { this.timer1.Enabled = false;//停止计时 button1.Enabled = true; button2.Enabled = false; label7.Text = ""; score = 100 * (problem_Nums - nums_wrong) / problem_Nums; label9.Text = "本次得分为:" + score.ToString(); }
5.1.5 改进后的分数类
public struct Fraction { private int x; private int y; //分母 public int Denominator { get { return y; } set { y = value; } } //分子 public int Element { get { return x; } set { x = value; } } }
5.2 计时功能
5.2.1 计时函数,将秒数转成hh:mm:ss的时间格式
private string GetAllTime(int time) { string hh, mm, ss; int s = time % 60; // 转化为秒 int m = (time / 60) % 60; // 分 int h = (time / 3600) % 60; // 时 //秒格式00 if (s < 10) { ss = "0" + s.ToString(); } else { ss = s.ToString(); } //分格式00 if (m < 10) { mm = "0" + m.ToString(); } else { mm = m.ToString(); } //时格式00 if (h < 10) { hh = "0" + h.ToString(); } else { hh = h.ToString(); } //返回 hh:mm:ss.ff return hh + ":" + mm + ":" + ss; }
5.2.2 计时器实现部分代码
/// <summary> /// 程序运行时加载窗体 /// </summary> private void Form1_Load(object sender, EventArgs e) { .......... //初始化时间 this.timer1.Enabled = false; this.timer1.Interval = 1000;//代表每秒改变一次时间 .......... } /// <summary> /// 点击开始按钮,产生一定数量的题目并开始计时 /// </summary> private void button1_Click(object sender, EventArgs e) { //计时器清零,并开始计时 t = 0; this.label10.Text = "00:00:00"; this.timer1.Enabled = true; ............ } /// <summary> /// 时钟控件事件,动态改变时间 /// </summary> private void timer1_Tick(object sender, EventArgs e) { t = t + 1; this.label10.Text = GetAllTime(t); }
5.3 记录用户对错数量
5.3.1 从文件中获取对错数量
private void init_Numbers() { StreamReader sr = null; try { sr = new StreamReader(path, Encoding.Default); this.correct_Number = int.Parse(sr.ReadLine()); this.wrong_Number = int.Parse(sr.ReadLine()); } catch { MessageBox.Show("文件打不开或者文件不存在", "文件打开错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { sr.Close(); } }
5.3.2 加载窗体和退出窗体时的文件操作
/// <summary> /// 程序运行时加载窗体 /// </summary> private void Form1_Load(object sender, EventArgs e) { //初始化对错数量 this.init_Numbers(); label11.Text = correct_Number.ToString(); label12.Text = wrong_Number.ToString(); ............ } /// <summary> /// 关闭当前窗体时保存对错数量 /// </summary> private void Form1_FormClosed(object sender, FormClosedEventArgs e) { StreamWriter sw = new StreamWriter(path, false); string text = correct_Number.ToString() + "\r\n" + wrong_Number.ToString(); sw.Write(text); sw.Close(); }
5.3.3 将对错数量清零
private void button5_Click(object sender, EventArgs e) { correct_Number = 0; wrong_Number = 0; //重置 StreamWriter sw = new StreamWriter(path, false); string text = correct_Number.ToString() + "\r\n" + wrong_Number.ToString(); sw.Write(text); sw.Close(); label11.Text = correct_Number.ToString(); label12.Text = wrong_Number.ToString(); }
5.4 语言切换
5.4.1 资源文件(繁体字)
5.4.2 添加代码来实现三种语言文字的切换
//在相应菜单选项单击事件函数中添加下面的代码 private void 英文ToolStripMenuItem_Click(object sender, EventArgs e) { Thread.CurrentThread.CurrentUICulture = new CultureInfo("en"); UpDataMainFormUILanguage(); } private void 中文简体ToolStripMenuItem_Click(object sender, EventArgs e) { Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh-CHS"); UpDataMainFormUILanguage(); } private void 中文繁体ToolStripMenuItem_Click(object sender, EventArgs e) { Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh-CHT"); UpDataMainFormUILanguage(); } //根据当前的语言区域,更新主窗口的语言信息 private void UpDataMainFormUILanguage() { rm = new ResourceManager(typeof(Form1)); UpDataForm1(rm); } //根据当前的语言区域,更新主窗口的语言 private void UpDataForm1(ResourceManager rm) { //菜单项 文件FToolStripMenuItem.Text = rm.GetString("start"); 查看历史记录ToolStripMenuItem.Text = rm.GetString("history"); 语言LToolStripMenuItem.Text = rm.GetString("language"); 中文简体ToolStripMenuItem.Text = rm.GetString("zh-CHS"); 中文繁体ToolStripMenuItem.Text = rm.GetString("zh-CHT"); 英文ToolStripMenuItem.Text = rm.GetString("English"); 帮助HToolStripMenuItem.Text = rm.GetString("help"); //按钮以及标签 label1.Text = rm.GetString("numbers"); label2.Text = rm.GetString("time_use"); label3.Text = rm.GetString("correct"); label4.Text = rm.GetString("wrong"); label5.Text = rm.GetString("question"); button3.Text = rm.GetString("submit"); button4.Text = rm.GetString("next"); button1.Text = rm.GetString("begin"); button2.Text = rm.GetString("end"); }
6.测试运行
未清零的正确题数和错误题数都会保存并显示,完成基本需求。
实现中文到英文,以及繁体字的转换。
完成指定题目之后点击结束得到所得分数。
当想要对正确和错误题目数清零时,点击清零即可。
整个软件完成了基本要求。
测试过程中出现了些许问题是因为开始没协调好,但是后来交流沟通后都得到了解决。
中程汇报
进展:完成计时器功能,完成用户对错数目统计,初步完成了相关需求。
问题:还没有完成多语言的功能,对于代码规范还没有解决。
问:你们用什么语言写的?
答:C#。
7.合作情况
7.1 2017282110284-章辉宇
这次项目中我和搭档分工合作,大体上我作为领航员提供主要的设计思路,我的搭档负责前端的设计和界面的实现,并且在我实现过程中给我提出意见避免了一些错误。一开始讨论总体设计思路,我们选出各自好的意见达成一致,然后分配各自任务,比如由我完成C++转换成C#,搭档给出前端设计,在此基础上就完成了基本GUI界面;然后对于各个功能,我们共同商讨解决方案,两个人通过交流极大扩宽思路,大大加快了设计的过程。在结对编程中,我们随时复审和交流,很好的提高了程序的初始质量。当然,在合作的过程也会遇到一些分歧,这时通过交流产生折中方案,或者上网查找资料寻找更好的方案,锻炼了各自的交流合作能力。
7.2 2017282110242-张宇光
张宇光2017282110242:当我在码代码的同时,伙伴对我的一些指导,给出的建议对于我们的工作都很有帮助,感觉比一个人进行工作的时候更加顺畅,总会发现自己平时注意不到的问题。当队友在进行编程时,自己在旁边观察,有一些自己不会的东西,在他进行工作的同时还可以教我许多不会的知识,受益匪浅。在遇到问题的时候会一起讨论解决问题,会出现多种不同的解决方式,经过讨论之后的解决方法可能不是最好的,但是一定是在某种程度上,我们都觉得不错的方案。在角色切换的过程中,会出现队友的代码有的地方自己不太懂,缺少注释的问题,对于这样的情况一般都会在后面再加上一些注释,给自己的队友作相应的解释。这一次的作业很大一部分是我的队友指导我做的,他的得分应该比我高一些,我还需要学习,有很多的不会的知识,向我的队友学习。
8.项目小结
8.1 2017282110284-章辉宇
此次项目中,我主要负责后端开发,通过代码的改写和新代码的编写过程提高了自己的编程能力。两点让我比较深刻:其一,之前作业写了一堆函数,如果直接拿来用代码相当混乱,于是将其整合成一个类,一下子让代码变得十分清晰明了;另外,在实现多语言切换让我学习到如何使用资源文件,如果直接使用代码赋值,编程相当麻烦并且不利于扩展,引入资源文件之后大大简化了代码,甚至可以让不懂编程的人通过简单修改就能添加新语言。还有,两个人的合作过程中,从搭档身上学到了一些新的思想,同时弥补了自己的几点不足。
8.2 2017282110242-张宇光
在此次的项目中,了解了结对编程中间可能会出现的一些问题,以及如何却解决相应的问题,在讨论的过程中对项目进行相应的改动。在解决问题的过程中,虽然是两个人,但是还是会存在一些不会的问题,有些想要实现的东西,由于时间和能力有限的关系,只能暂时搁置,能力还需要提升,不能得过且过。在写代码过程中,对于文件的调用以及修改还并不是很熟悉,缺少了某些关键步骤的时候,始终都解决不了,然后死脑筋觉得自己写的没问题,但是经过伙伴的指导之后,还是发现了问题,在出现问题的时候还是需要多找找资料之类的,能力不足的地方需要努力。在提交代码的过程中,并没有实时更新,最后两天找到以前的版本进行提交,再将最终的版本提交,所以只能看到我们组的两次提交,这个对于老师观察我们的进度有些影响,下次会进行改进。
9.结对照片
10.PSP
PSP2.1 | Personal Software Process Stages | 实际耗时(分钟) |
---|---|---|
Planning | 计划 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 20 |
Development | 开发 | 1425 |
· Analysis | · 需求分析 (包括学习新技术) | 100 |
· Design Spec | · 生成设计文档 | 40 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 40 |
· Design | · 具体设计 | 110 |
· Coding | · 具体编码 | 1000 |
· Code Review | · 代码复审 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 45 |
Reporting | 报告 | 100 |
· Test Report | · 测试报告 | 45 |
· Size Measurement | · 计算工作量 | 35 |
·Postmortem& Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 |
合计 | 1545 |