四则运算之GUI

Posted Ai007

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四则运算之GUI相关的知识,希望对你有一定的参考价值。

四则运算之GUI

Coding克隆地址:https://git.coding.net/lvgx/pair_programming.git
 

目录:

一、前言

二、计划时间——PSP

三、接口设计

四、接口实现

五、性能分析

六、单元测试

七、异常处理

八、模块设计

九、模块对接

十、她

十一、结对编程思考

十二、实际时间——PSP

 


一、前言

首先我很感谢我的队友——吕国馨(www.cnblogs.com/lvgx/p/8733486.html),谢谢她清明假期仍在认真的敲代码,放弃自己休息的时间。第二我要感谢一位大佬,当我对GUI没丝毫头绪时,大佬的一篇博客给了我启发。

下面带上大佬博客:www.cnblogs.com/mafx/p/8536796.html

二、计划PSP

 

PSP

任务内容

计划时间(min)

Planning

计划

30

     Estimate

    估计这个任务需要多少时间,并规划大致工作步骤

30

Development

开发

35*60+25

    Analysis

    需求分析

60

    Design Spec

    生成文档

0

    Design Review

    设计复审

2*60

    Coding Standard

    代码规范

10

    Design

    具体设计

12*60

    Coding

    具体编码

2*8*60

    Code Review

    代码复审

4*60

    Test

    测试

15

Reporting

报告

5.5*60

    Test Report

    测试报告

60

    Size Measurement

    计算工作量

30

   Postmortem& ProcessImprovement Plan

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

4*60

尤其在编程GUI时候,花费了大量的时间。

三、接口设计

1、Information Hiding

信息隐藏是指在设计和确定模块时,对于用不到的信息是禁止访问的。封装:比如求圆的面积,你只需要调用getArea(r);即可,不需要知道他是如何运行的。宏定义:可以用宏定义对信息进行隐藏,比如#define PI 3.1415926。当你需要使用π时,直接使用PI就行了,你不需要知道PI的具体值。

我们的设计:进行模块化设计,通过对函数的封装。只可以调用方法,不可以改变内部变量。界面化设计:你只需要知道如何使用它,不需要知道界面内部是如何运行的。变量设置为私有的。

2、Interface Design, Loose Coupling

 接口设计和低耦合是相辅相成的,接口化设计能大大降低程序的耦合度,低耦合一定离不开接口化设计。个人理解:接口化设计就是模块化设计,让不同方法放入到不同类中,并且使得各个类相互独立,减少关联性。低耦合和接口化设计差不多,使得各个模块之间减少依赖性,从而提高容错率。

我们的设计:我们已经尽我最大的努力,来进行模块化设计了,比如界面生成和算式生成是相互独立的,优先级判断、计算结果和算式生成又是相互独立的。但是我们的程序还有很多不足,比如界面设计,我们的五个界面都在同一个函数中实现的。原本我们尽力让他们在不同函数中,但是在继承时过程中,总是出现错误,最后我们还是放弃了。Java的继承我们还要再学一学。

四、接口实现

 本次界面程序一共用到了9个类,14个函数,此9个类的调用关系如下图:

我们此界面程序的关键之处在于监听器的运用,大概用到了3个监听器,分别是复选框监听器、按钮监听器、文件监听器,本打算使用时间监听器,来计算当前时间和用时,但是发现可以直接调用java中自带的类,方便起见,就没有使用。代码的独特之处在于:界面套界面。即是亮点又是污点,亮点在于方法简单,实现方便,容易掌握(灵感来源于:www.cnblogs.com/mafx/p/8536796.html)。同时这也是一个不好之处,导致程序无法分解,耦合度太高,后期维护困难。

五、性能分析

说句实话,自我感觉能完成这个项目就很不错了,还要什么性能优化呀。。。但是我们已经尽力优化性能了,比如挺高代码利用率了。比如Puanduan类,和Yunsuan类,我们把它两生成两个类,其他类直接调用,减少代码长度。尽量减少内存开支,比如不定义数组,改用容器,因为数组的每个存储单元利用率不高。一般数组我们都往大的开,因为怕其不够用,但是这种方法会导致,大量内存单元没有被利用。题目要求最大生成10000到题目,如果你开10000大小的数组,当我们只生成10道题时,会有99990个内存没被利用。我们还尽量减少循环套循环,从而减少时间的消耗。

如何性能分析?百度上说是,进行溢出测试,将代码进行死循环,使得当CPU达到100%时,查看时间,时间越短,性能越好。

我们的分析方法是:通过JProfiler,进行性能分析。

总体分析图:包括CPU,内存,线程等等。

性能分析过程:

我们用三组数据分别对三个主要函数进行时间上的测试:

函数一:Algorithm函数,他用时最短,只用了11640微妙,且30%的原因在于文本的输入与输出,这是无法避免的,所以未进行优化。

函数二:Algorithm2函数,用时37789微妙,此函数30%的用时是在调用JiSuan函数上,JiSuan的用时主要是在出栈上,也是无法避免的。

函数三:Algorithm1函数用时最长,用时60390微妙,此函数用时主要是循环,此函数中有一个三重循环和大量二重循环,导致了时间过长。从图像也可以看出,橙色占的比例接近90%(橙色代表,阻碍与消耗,不是正常运行程序时间)。

 

性能优化:对于循环过多的Algorithm1函数,进行了优化,减少了几个循环,之后,我们又减少了大量循环,因为老师的需求降低(中间过程可以保证不再范围之内,这使得我们的程序,更加简洁)

 

可见,时间明显降低!

我们还对界面程序的性能进行分析,和优化,改进,文件也通过ps.close();进行关闭,按F4再一次查看,内存占用率明显减少,文件也都关闭了,但是仍有内存没释放,我们会继续改进的,性能分析结果如下。

六、单元测试

测试单元代码:

 1 public class Test {
 2     
 3     private static int n=10;
 4     private static int m1=1;
 5     private static int m2=50;
 6     private static int o=4;
 7     private static int c=0;    
 8     private static String s="11+(43-(35-(14+26)))";
 9     
10     public static void main(String[] args) {
11         // TODO Auto-generated method stub
12         Command.main(null);// 主界面
13         System.out.println(Algorithm.Algorithm(n, m1, m2, c, o)); //生成题目函数一
14         System.out.println(Algorithm.Algorithm(n, m1, m2, c, o)); //生成题目函数二
15         System.out.println(Algorithm.Algorithm(n, m1, m2, c, o)); //生成题目函数三
16         GUI.main(null);  // 中文界面
17         GUI1.main(null); // 英文界面
18         //JiSuan.JiSuan(s);
19     }
20 
21 }

我们对9个类进行了测试:采用结合或者独立的测试方法,来分别观察其代码覆盖率。(表中分别为:函数名、覆盖率、执行行数、错过行数、总行数)

第一组数据:

Command.java:这是一个语言选择窗口。

Algorithm.java:是一个可以生成加减乘除并且带有括号式子的类。

JiSuan.java:是一个可以计算式子,并且返回结果的类。

Panduan.java:是一个判断运算符优先级的类

测试结果如下:

第二组数据:

GUI.java和GUI1.java:分别是生成汉语出题窗口和英语出题窗口、汉语上传文件和英语上传文件的窗口。测试结果如下:

第三组数据:

YunSuan.java:一个进行简单加减乘除运算的类。测试结果如下:

第四组数据:

Algorithm1.java:是一个能生成乘除不带括号和不带乘除不带括号式子的类。测试结果如下:

Algorithm2.java:是一个生成不带乘除带括号式子的类。测试结果如下:

 

总体来说,代码覆盖率为:91.47%

七、异常处理

 异常处理一:就是对输入出题数、运算符个数、范围等进行判断,判断其是否合法或者超出其范围。(只展示了,出题数的代码,其他雷同)

 1 try {
 2     n1 = Integer.parseInt(n.getText());
 3     if (n1 <= 0 || n1 > 10000) {
 4         n.setText("n的范围不在[1,10000]内,请重新输入");
 5         return;
 6     }
 7     flag0 = 1;
 8 } catch (Exception a) {
 9     n.setText("n的格式不合法,请重新输入!");
10 }

对应场景:

异常处理二、文件异常处理

1 try {
2     ps = new PrintStream("result.txt");// 生成文件
3     System.setOut(ps);
4 } catch (Exception e) {
5     System.out.println("文件生成错误");// 提示
6 }

对应场景:

点击出题时,如果文件生成错误,将不再生成。

异常处理三:文件过滤

1 FileNameExtensionFilter filter = new FileNameExtensionFilter("war", "xml", "txt", "doc", "docx");

对应场景:

只能找到此格式的文件,其他格式文件,都被过滤了。

异常处理四:编码异常

1 InputStreamReader read = new InputStreamReader(new FileInputStream(f), "UTF-8");

对应场景:

只能处理UTF-8文件,要不会出现乱码。

异常处理五:用户不存在异常

如果你没有注册,即文件中没你的用户信息,会报用户不存在异常。

 1 int flag = yanZheng(user.getText(), password.getText());
 2 if (flag == 1) {
 3     GUI.main(null);
 4 } else if (flag == 0) {
 5     user.setText("密码错误!");
 6     return;
 7 } else {
 8     user.setText("账号不存在!");
 9     return;
10 }

对应场景:

 

  异常处理六:用户和密码不匹配

即当用户存在时,但是密码输入和注册时的不同时,会报密码错误。代码如上:

对用场景:

  异常处理七:用户已存在

即当注册过程中,如果该用户已存在,会报用户已存在错误。

1 int temp = yanZheng(user.getText(), password.getText());
2 if(temp==0||temp==1)
3 {
4     user.setText("账号已存在,请重新注册!");
5     return ;
6 }

对应场景:

异常处理八:注册信息不合法

注册时,对账号和密码有一定限制,当超出限制时,会报错。

 1 try {
 2     int user1 = Integer.parseInt(user.getText());
 3     if (user1 <= 0 || user1 >= 1000000) {
 4         user.setText("用户名多余6位,或者不合法!");
 5         return;
 6     }
 7 } catch (Exception a) {
 8     user.setText("账号有多余字符(只能是数字),请重新注册!");
 9     return;
10 }
11 try {
12     int password1 = Integer.parseInt(password.getText());
13 } catch (Exception a) {
14     user.setText("密码有多余字符(只能是数字),请重新注册!");
15     return;
16 }

  为了方便起见,限制有点严格,必须是数字字符串,而且不能超过6位,其实不太合理,但是程序实现很简单。

对应场景:

八、模块设计

1、首先先设计一个语言选择功能,可以进行语言选择,通过按钮和调用函数来实现。

 1 private JButton jcChina = new JButton("中文");//两个按钮,分别生成两种不同语言的界面
 2 private JButton jcEnglish = new JButton("English");//可以用一个数组,存入多种语言,实现多语言转化
 3 jcChina.addActionListener(new ActionListener() {//按钮监听器,为了实现中文界面
 4     @Override
 5     public void actionPerformed(ActionEvent e) {
 6         GUI.main(null);
 7     }
 8 });
 9 jcEnglish.addActionListener(new ActionListener() {//按钮监听器,为了实现英文界面
10     @Override
11     public void actionPerformed(ActionEvent e) {
12         GUI1.main(null);
13     }
14 });

2、然后进行出题界面设计,此界面就是简单的GUI界面设计。

 1 JPanel p1 = new JPanel();
 2 p1.setLayout(new GridLayout(4, 2, 5, 5));
 3 p1.add(new JLabel("出题数[1,10000]:"));
 4 p1.add(n);
 5 p1.add(new JLabel("数值左边界[1,100]:"));
 6 p1.add(m1);
 7 p1.add(new JLabel("数值右边界[50,1000]:"));
 8 p1.add(m2);
 9 p1.add(new JLabel("运算符数[1,10]:"));
10 p1.add(o);

3、然后进行上传文件的界面设计,此界面可以直接调用,java中已经有了。

1 JFileChooser chooser = new JFileChooser();
2 chooser.setMultiSelectionEnabled(true);
3 // 过滤文件类型 
4 FileNameExtensionFilter filter = new FileNameExtensionFilter("war", "xml", "txt", "doc", "docx");
5 chooser.setFileFilter(filter);

4、然后设计答题界面设计,此界面和出题界面类似,但是调用方法不同,在下面我会讲到。

 1 JPanel panel2 = new JPanel();
 2 JTextField text = new JTextField(10);
 3 panel2.setLayout(new GridLayout(3, 2, 5, 5));
 4 label.setText(addProblem());
 5 panel2.add(label);
 6 panel2.add(new JLabel("/*为了美观*/"));
 7 panel2.add(new JLabel("请输入答案:"));
 8 panel2.add(text);
 9 panel2.add(jbnext);
10 panel2.add(jbsubmit);

5、统计页面设计,内容设计,改用调用list实现。

1 JPanel panel = new JPanel();
2 panel.add(new JLabel(
3         "做题总数: " + size + " " + "  正确数:" + rightAnswer + "  用时(S):" + (t2 - t1) / 1000));
4 setLayout(new GridLayout(100, 1, 5, 5));
5 for (int i = 0; i < size; i++) {
6     panel.add(new JLabel(list.get(i)));
7 }
8 resultFrame.add(panel);

九、模块对接

1、语言选择功能

 

相当于主函数,它通过按钮调用GUI和GUI1类

2、出题功能

它也是通过按钮调用做题界面和上传界面。

 

 

3、做题功能

通过下一题按钮进行判断和再次出题,通过按钮调用统计界面。

 

4、统计和计时

最终页面,不进行调用。代码如下:

 

5、上传文件及解析

代码如下:

 

调用提交和下一题按钮,代码和上面一样,但是会有一个上传成功的提示,代码如下:

 6、用户注册和登录功能

没有注册的用户必须注册后才能进入程序进行答题和出题界面。

通过按钮对模块之间进行连接。

十、她

我们原本打算做前端,即Web的四则运算程序,而且她已经完成了,前端开发,如图:

 

但是由于我不会套页,即不能和后端连起来。所以最后放弃了Web项目,改做GUI。让她白做了一场,惭愧(就当给她个机会,让她练习练习前端知识了,嘻嘻)。

1、她:优点:技术强;聪明;乐观。缺点:做事不认真。

2、我:优点:认真,上进,创造性思维强。缺点:模块化思维欠缺。

十一、对编程思考

结对编程有好处:

一、可以减轻两个人的压力。

二、相互学习、相互指正。

三、增强两个人的关系,增强合作能力、增强代码理解能力。

四、分工明确,增加办事效率。

结对编程有坏处:

一、如果交流不到位,那所做的项目将会功亏一篑。比如这次项目,因为我们前期交流没有到位,导致Web项目进行到一半,就进行不下去了。

二、两个人各做各的,导致后期两者的项目结合比较困难。

三、两人的分工不均匀,比如技术强的人可能做得就比较多,技术差可能就会抱大腿。

四、要花费大量时间进行交流和解释项目,毕竟代码不好看懂。

十二、实际PSP

 

PSP

任务内容

完成时间(min)

Planning

计划

60

     Estimate

    估计这个任务需要多少时间,并规划大致工作步骤

60

Development

开发

45*60

    Analysis

    需求分析

45

    Design Spec

    生成文档

0

    Design Review

    设计复审

3*60

    Coding Standard

    代码规范

15

    Design

    具体设计

12*60

    Coding

    具体编码

3*8*60

    Code Review

    代码复审

4*60

    Test

    测试

60

Reporting

报告

9*60

    Test Report

    测试报告

0

    Size Measurement

    计算工作量

60

   Postmortem& ProcessImprovement Plan

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

8*60

 

 


 

对于附加功能多语言,我们实现了两种语言的转换,其实可以通过数组实现多种语言转换,也可以通过我这种方法实现,即在生成一个界面。这种方法的好处在于简单,坏处在于代码比较多,还琐碎。

对于附加功能多用户,我们的这个GUI界面程序,可以多人下载,多人使用,实现多用户同时在线。用户必须登陆后才能进行上传题目、出题、做题等功能的使用,还可以统计用户人数。

参考网站:

www.cnblogs.com/mafx/p/8536796.html  //基本的GUI语法

https://zhidao.baidu.com/question/184288577.html  //上传文件语法

https://www.cnblogs.com/happyzm/p/6530384.html //覆盖率教程

 

以上是关于四则运算之GUI的主要内容,如果未能解决你的问题,请参考以下文章

结队编程-基于gui的四则运算生成器

结对作业1----基于GUI的四则运算生成器

结对作业1----基于GUI的四则运算生成器

四则运算GUI设计2.0

四则运算GUI设计2.0

使用底图作为Python GUI中的图形