2023软工作业(一)——计算器

班级班级社区
作业要求软件工程实践第一次作业-CSDN社区
作业目标完成一个具有可视化界面的科学计算器
参考文献Fyne

  目录

作业要求

项目源码地址

作业目标

0. 界面及功能展示

1. PSP表格

2. 解题思路描述

3. 核心代码

4. 设计与实现过程

5. 程序性能改进

6. 单元测试展示

7. 异常处理

8. 心路历程和收获


环境:go 1.20.7   |  windows  |  mingw64

编程工具: VS Code

作业要求

要求链接软件工程实践第一次作业-CSDN社区要求链接

项目源码地址

代码地址

作业目标

完成一个具有可视化界面的科学计算器

0. 界面及功能展示

                软工计算器演示


1. PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3030
• Estimate• 估计这个任务需要多少时间2015
Development开发300340
• Analysis• 需求分析 (包括学习新技术)6090
• Design Spec• 生成设计文档2020
• Design Review• 设计复审3030
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)1010
• Design• 具体设计3050
• Coding• 具体编码240300
• Code Review• 代码复审6030
• Test• 测试(自我测试,修改代码,提交修改)100100
Reporting报告120100
• Test Repor• 测试报告2020
• Size Measurement• 计算工作量1010
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划90

70

合计900915

2. 解题思路描述

        1. GUI问题

        什么是GUI,如何使用GUI ,通过调用特定的GUI库实现的接口,可以实现GUI的窗口创建,窗口布局,按钮布局,设置函数响应等功能

        2. 计算表达式

        用户输入表达式字符串,程序需要识别该字符串,包括识别数字,运算符等,比较难的是括号匹配问题,这边选择通过堆栈实现括号的匹配问题,但是在三角函数方面这个并不适用,这里选择使用的是递归实现

3. 核心代码

func equals() func() {return func() {// 切割换行lines := strings.Split(entry.Text, "\n")fmt.Println("lines:", len(lines))// 空表达式不变if len(lines) == 0 || (lines[0] == "" && len(lines) == 1) {entry.Text = ""entry.Refresh()log.Println("empty expression")return}line := lines[len(lines)-1]// 错误切除if len(lines) >= 3 || strings.Contains(entry.Text, "error") {entry.Text = lineif strings.Contains(lines[0], "error") {entry.SetText("")log.Println("continue error calculate")return}entry.Refresh()}// 溢出切除if strings.Contains(line, "Inf") {entry.SetText("error:inf calculate\n")entry.Refresh()log.Println("error:inf calculate")return}// 三角函数处理for {if strings.Contains(line, "sin") || strings.Contains(line, "cos") || strings.Contains(line, "tan") {res, err := Hsin(line)if err != nil {entry.SetText("error:sin or cos calculate expression\n")entry.Refresh()log.Println(err)return}log.Println("--------------------")_, _, trim_exp, err := TrimTec(line)if err != nil {entry.SetText("error:sin or cos trim expression\n")entry.Refresh()log.Println(err)return}log.Println("--------------------")line = strings.Replace(line, trim_exp, fmt.Sprint(float32(res)), 1)log.Println("line 三角函数切割 :", line)} else {break}}line = strings.Trim(line, "+/x")// 次方替换if strings.Contains(line, "^") {line = strings.ReplaceAll(line, "^", "**")}// 到此阶段只剩下基本的表达式,高级的运算符已经处理成数字和基本运算符// 表达式求值expr, err := govaluate.NewEvaluableExpression(line)if err != nil || expr == nil {if strings.Contains(err.Error(), "transition") {entry.Text = fmt.Sprint("transition error")}entry.Text = fmt.Sprint("error:wrong expression\n")entry.Refresh()return}result, err := expr.Evaluate(nil)if err != nil || result == nil {if strings.Contains(err.Error(), "transition") {entry.Text = fmt.Sprint("transition error")}entry.Text = fmt.Sprint("error:unespected error please clear\n")}entry.Text += "=\n"entry.Text += fmt.Sprint(result)entry.Refresh()}
}

递归求三角函数

// 求解表达式的第一个三角函数值
func Hsin(exp string) (float64, error) {restr := ""preindex := 0lastindex := 0pkcnt := 0lkcnt := 0begin := falsesin := falsetan := falserjudge := falseif strings.Contains(exp, "sin") || strings.Contains(exp, "cos") || 
strings.Contains(exp, "tan") {for index, v := range exp {ch := string(v)if begin && ch == "(" {pkcnt++} else if begin && ch == ")" {lkcnt++if lkcnt == pkcnt { //括号匹配lastindex = indexrestr = exp[preindex+3 : lastindex]break}}if ch == "r" {rjudge = true}if (ch == "i" || ch == "o" || ch == "a") && !begin {preindex = indexlog.Println("--------------")begin = true}if ch == "s" && !begin {sin = true} else if ch == "t" && !begin {tan = true}}if pkcnt != lkcnt {log.Println("error expresiion")return 0, errors.New("error expresiion")}exp = restr} else {expr, err := govaluate.NewEvaluableExpression(exp)if err != nil || expr == nil {log.Println("expression:", exp)log.Println("error expresiion1")return 0, err}result, err := expr.Evaluate(nil)if err != nil {log.Println("error expresiion2")return 0, err}log.Println("output:", result.(float64))return result.(float64), nil}log.Println("exp:", exp)result, err := Hsin(exp)if err != nil {return 0, err}if sin {log.Println("sin------:", result)if rjudge {if !judgeValue(result) {return 0, errors.New("error:value error")}return math.Asin(result) * 180 / math.Pi, nil}return math.Sin(result * math.Pi / 180), nil} else if tan {log.Println("tan------:", result)if rjudge {return math.Atan(result) * 180 / math.Pi, nil}return math.Tan(result * math.Pi / 180), nil}if rjudge {if !judgeValue(result) {return 0, errors.New("error:value error")}return math.Acos(result) * 180 / math.Pi, nil}log.Println("cos------:", result)return math.Cos(result * math.Pi / 180), nil
}// 获得第一个cos或者sin表达式
func TrimTec(exp string) (preindex, lastindex int, res string, err error) {begin := falsepkcnt := 0lkcnt := 0rjudge := falsefor index, v := range exp {if string(v) == "r" && !begin {rjudge = true}if (string(v) == "s" || string(v) == "c" || string(v) == "t") && !begin {preindex = indexbegin = true}if begin {if string(v) == "(" {pkcnt++} else if string(v) == ")" {lkcnt++if lkcnt == pkcnt {lastindex = indexlog.Println("preindex:", preindex)log.Println("lastindex:", lastindex)if rjudge {res = exp[preindex-1 : lastindex+1]return}res = exp[preindex : lastindex+1]return}}}}err = errors.New("error:expression error")return
}


4. 设计与实现过程

导入所需的库:

fyne:GUI库,用于创建GUI窗口,编排GUI布局,  自定义图形化界面,内嵌处理函数

math:提供数学计算方法 和 数学常量, 如: Π

创建计算器窗口:

创建一个fyne窗口,设置logo,设置显示位置,窗口大小。

创建显示输入和输出的文本框:

创建一个Entry(文本框)部件的对象,用于显示输入输出。
可以使用entry.SetText("内容")来设置文本框中的内容,或者直接对entry.Text进行操作

每次操作完后需要entry.Refresh刷新,用户才能实时的在文本框中获取最新的内容
设置文本对齐方式、边框大小等属性。

响应函数:

input :input函数用于输入用户在按钮输入的内容如数字,运算符, 支持过滤连续输入运算符
 

equls:equals函数用于处理表达式并返回结果,使用堆栈,递归以及调用库的方式实现表达式的计算,这个方法中不仅计算的细节很多,处理错误的细节也要注意

计算错误时,返回error:错误内容,用户只需要再次输入新的内容则会清空文本框并开启新的输入,或者直接点击清空按钮   c

sign:sign函数用于将传入的数进行正负切换

        

back:back函数用于 删除表达式最后一个字符

其他内置函数:
        Hsin 获得第一个cos或者sin表达式

        TrimTec 获得第一个cos或者sin表达式

        judgeValue 判断反三角函数输入值是否在定义域内

文本框和按钮布局顺序:

包括科学函数按钮、操作符按钮、数字按钮、等号等。
使用循环创建按钮,并为每个按钮绑定相应的事件处理函数。

最后启动窗口即可


5. 程序性能改进


优化方式:使用递归识别并计算表达式中的三角函数值,降低时间复杂度,代码可见3. 核心代码中的Hsin函数

6. 单元测试展示

覆盖率测试结果(这边仅测试主要功能函数,另外的百分之二十九左右为程序的启动函数,例如GUI布局设置,窗口创建之类的代码这边不包含进去,覆盖率实现基本全覆盖)

覆盖率测试代码

func TestCover(t *testing.T) {a := app.New()_ = a.NewWindow("Calculator")entry = widget.NewEntry()entry.MultiLine = trueentry.Resize(fyne.NewSize(150, 150))funcs := equals()// 表达式测试 各种运算符检测 结果检测entry.Text = "1+2+3+2^3+rsin(sin(30))+rtan(tan(30))+rcos(cos(60))"t.Log(entry.Text)funcs()entry.Text = "error:xxx"funcs()entry.Text = "Inf"funcs()entry.Text = "rsin(10)"funcs()entry.Text = "rcos(10)"funcs()// 重复运算符过滤ifunc := input("+")ifunc()ifunc()// 正负反转entry.Text = "3"sfunc := sign()sfunc()entry.Text = "3.3"sfunc()// 退格测试entry.Text = "8^9999"bfunc := back()bfunc()funcs()entry.Text = "\n"bfunc()entry.Text = ""bfunc()t.Log(entry.Text)
}

覆盖率优化经验:增加测试用例,尽可能地将代码的错误都跑过一遍,主要还是看编程人对自身代码的熟悉程度,需要了解每个异常发生原因以及每个分支的进入条件,编写相应的测试用例

单元测试代码

func TestCalculateSC(t *testing.T) {// 1.判断表达式是否有三角函数// 2.有则放入Hsin求得第一个函数的值// 3.然后将值替换原本的三角函数// 4.回到1// 5.没有三角函数了在将整个表达式求解exp := "1+sin(sin(10+110))+rsin(0.5)"for {if strings.Contains(exp, "sin") || strings.Contains(exp, "cos") {res, err := Hsin(exp)if err != nil {t.Log(err)t.Fail()}_, _, trim_exp, err := TrimTec(exp)if err != nil {t.Log(err)t.Fail()}exp = strings.Replace(exp, trim_exp, fmt.Sprint(float32(res)), 1)t.Log("change", exp)} else {break}}}func TestEvaluate(t *testing.T) {expr, err := govaluate.NewEvaluableExpression("1+3%4-1/2+2^3")if err != nil || expr == nil {fmt.Println("err:", err)t.Log("error")t.Fail()}result, err := expr.Evaluate(nil)t.Log("res:", result)
}

单元测试结果

 

7. 异常处理

随着程序的开发,有些细节的错误没有处理会导致程序直接崩溃,闪退

如: 表达式输入错误,返回的值无法表示时返回Inf,输入的值不在数学函数的定义域之内,用户和程序显示内容不同步等错误

  

大部分的错误只需要处理好临界条件即可,在golang 中函数返回错误,然后在函数返回后判断返回的错误是否为空即可进入分支处理,同时有些库函数并不返回错误,因此还是需要好好处理临界的条件判断,如输入值是否在定义域内,我们需要在计算前判断一下输入值的大小,如果不满足则直接返回错误不进行后续的操作

再比如:返回的值无法表示的时候返回INF ,程序在判断用户输入时,需要判断表达式内是否含有INF字符串,存在则返回表达式错误


8. 心路历程和收获


心路历程:先想到的是GUI编程,之前只开发过Web,并没有windows GUI相关经验,然后去百度了解,搜索相关的资料,GUI的用法之类的,然后想到的表达式的处理,这是一个相对比较复杂的过程,我通过自己实现内部函数递归算法和调用库函数的方式实现了表达式的计算,这里面有很多细节需要考虑,不过我认为在这门课中本次任务的目标还是对GUI的使用,毕竟换个环境或者题目这些细节可能又需要重新去考虑

用户界面使用优化:在一开始实现的过程中,总是会遇到感觉很别扭的地方,比如闪退,返回错误显示在文本框还要再次点击清空才能再次输入表达式,我通过自身体验去优化这些地方,使得用户不会出现闪退,以及能够在发生错误后只需点击任一按钮即可清空并开始新的表达式输入

学习收获:收获了关于GUI库:fyne的使用、字符串处理,计算表达式处理,单元测试,和GUI编程经验

总结:了解了GUI编程的相关知识,锻炼了GUI编程能力,
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/143719.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt扫盲-QSqlRelationalTableModel 理论总结

QSqlRelationalTableModel 理论总结 一、概述二、使用概述三、常用 一、概述 QSqlRelationalTableModel的行为类似于QSqlTableModel,但允许将列设置为进入其他数据库表的外键。 二、使用概述 在上面左边的截图显示了 QTableView 中的普通 QSqlTableModel。外键(…

分类预测 | MATLAB实现WOA-CNN-GRU-Attention数据分类预测

分类预测 | MATLAB实现WOA-CNN-GRU-Attention数据分类预测 目录 分类预测 | MATLAB实现WOA-CNN-GRU-Attention数据分类预测分类效果基本描述模型描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现WOA-CNN-GRU-Attention数据分类预测,运行环境Matlab2021b及以上&…

Ubuntu 安装PostgreSQL

网上有各种版本的,也可以去官网看官方的文档。我是下载的PostgreSQL-11.4版本的。找到以后直接复制网上的压缩包链接就可以。 $ mkdir /opt/postgresql && cd /opt/postgresql $ wget https://ftp.postgresql.org/pub/source/v11.4/postgresql-11.4.tar.gz…

基于规则架构-架构案例2019(三十九)

电子商务 某电子商务公司为了更好地管理用户,提升企业销售业绩,拟开发一套用户管理系统。该系统的基本功能是根据用户的消费级别、消费历史、信用情况等指标将用户划分为不同的等级,并针对不同等级的用户提供相应的折扣方案。在需求分析与架…

运行软件mfc100u.dll缺失是怎么办?mfc100u.dll丢失解决方法分享

Mfc100u.dll 丢失的问题可能困扰着许多使用计算机的用户。Mfc100u.dll 是一个重要的动态链接库文件,它包含了许多功能模块,如字符串处理、数学计算、文件操作等。当 Mfc100u.dll 文件丢失或损坏时,可能会导致许多应用程序无法正常运行&#x…

OS 模拟进程状态转换

下面的这个博主写的很好 但是他给的代码print部分和语言风格python三识别不了 这个特别感谢辰同学帮我调好了代码 我放在主页上了 估计过两天就可以通过了 《操作系统导论》实验一:模拟进程状态转换_process-run.py-CSDN博客 这个补充一下他没有的:OS…

基于yum制作kylin系统docker镜像

注意,由于线上源版本与iso源存在差异,应采用iso源制作docker镜像 [rootlocalhost yeqiang]# yum install --installroot/home/yeqiang/kylin-docker/ yum 无法找到发布版本(可用 --releasever 指定版本) 警告:加载 /e…

正交对角化,奇异值分解

与普通矩阵对角化不同的是,正交对角化是使用正交矩阵对角化,正交矩阵是每列向量都是单位向量,正交矩阵*它的转置就是单位矩阵 与普通矩阵对角化一样,正交对角化的结果也是由特征值组成的对角矩阵 本质还是特征向量对原矩阵的拉伸…

【Java】异常

1. Java的异常概念 1.1 异常体系结构 从上图中可以看到: 1. Throwable:是异常体系的顶层类,其派生出两个重要的子类, Error 和 Exception 2. Error:指的是JVM无法解决的严重问题,比如:JVM的内部错误、资源…

澳大利亚新版《2023年消费品(36个月以下儿童玩具) 安全标准》发布 旨在降低危险小零件的伤害

2023年9月4日,澳大利亚政府发布了新的儿童玩具强制性安全标准《2023年消费品(36个月以下儿童玩具)安全标准》(Consumer Goods (Toys for Children up to and including 36 Months of Age) Safety Standard 2023)。该强制性标准旨在尽可能地降…

MySQL学习笔记20

备份过程需要考虑的因素: 1、必须制定详细的备份计划(策略)(备份频率、时间点、周期)。 一天做一次增量、一周做一次全量。 2、备份数据应该放在非数据本地,并建议多份备份。 可以放在另外一台服务器上…

python使用mitmproxy和mitmdump抓包以及对手机

mitmproxy是一个中间人角色,供python抓包使用。 本机环境:win10 64位,python3.10.4。首先安装mitmproxy,参考我的文章 记录一下python2和python3在同一台电脑上共存使用并安装各自的库以及各自在pycharm中使用的方法-CSDN博客 一…

Nginx的反向代理、动静分离、负载均衡

反向代理 反向代理是一种常见的网络技术,它可以将客户端的请求转发到服务器群集中的一个或多个后端服务器上进行处理,并将响应结果返回给客户端。反向代理技术通常用于提高网站的可伸缩性和可用性,并且可以隐藏真实的后端服务器地址。 #user…

Servlet开发-通过代码案例熟悉HttpServletRequest类

关于Servlet开发的流程推荐看servlet开发-通过Tomcat部署一个简单的webapp Servlet开发与idea集成的插件安装推荐看idea集成tomcat(Smart Tomcate插件安装) postman(第三方创建HTTP请求工具)的安装推荐看创建HTTP请求的几种方式…

组网行动指南:打造对跨国企业友好的专用网络环境

在全球数字化转型的浪潮下,越来越多的企业跨国发展业务,由于跨域网络的复杂性和自建网络架构的各种限制,导致分散在不同地理位置的站点无法实现数据互通和协作。 跨国企业组网常见痛点 痛点一:自建网络方案经常掉线,影…

【如何看待Unity收费】对标中小公司的待就业者的该如何做

👨‍💻个人主页:元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏:Uni…

【红日靶场】vulnstack2-完整渗透过程

文章目录 一、网络拓扑二、描述配置环境渗透开始信息收集开始攻击干掉杀软cs上线权限提升 内网探测横向移动再次横向rdp连接痕迹清除 总结: 一、网络拓扑 网络配置: 二、描述 红队实战系列,主要以真实企业环境为实例搭建一系列靶场&#x…

多线程的学习中篇下

volatile 关键字 volatile 能保证内存可见性 volatile 修饰的变量, 能够保证 “内存可见性” 示例代码: 运行结果: 当输入1(1是非O)的时候,但是t1这个线程并沿有结束循环, 同时可以看到,t2这个线程已经执行完了,而t1线程还在继续循环. 这个情况,就叫做内存可见性问题 ~~ 这…

再生之术:遗忘 Root 密码的 CentOS8 Stream 解决方案

文章目录 大魔头 RootGRUB 引导界面BootLoaderGRUB主要功能选择启动的操作系统编辑内核启动参数 进入GRUB 引导界面编辑内核启动参数单用户模式 进入内核编辑界面rd.break进入单用户模式 大魔头 Root 哈哈,你好!今天,让我们来聊聊 Linux 系统…

ElementPlus· tab切换/标签切换 + 分页

tab切换 ---> <el-tabs><el-tab-pane>... 分页 --------> <el-pagination> tab切换 // tab标签切换 // v-model双向绑定选项中的name&#xff0c;tab-change事件在 activeName改变时触发 <script setup> const tabChange (tab, event)>{…