实用计算器程序
图4等号按键响应函数流程图
用户输入完计算式后可以按下等号如图4计算结果,它的核心是调用了一个自己写的WorkR()函数计算最后的结果。但在之前需要判断是否真的需要计算,如果Edit控件中显示的是一个算好记忆条,那么直接截取记忆条等号后的结果出来显示就行了。
图5WorkR函数流程图
如图5所示进来的算式先判定括号的对数以及左右括号是否匹配,完全正确才能开始计算。它通过cket函数、cut函数、GetStr函数和GetResult函数,最后得到一个不含括号的算式,再通过GetStr函数和GetResult函数得到最后的结果。
针对用户的c类操作,我的对策是在每个计算按键中写入判断语句,如果是计算过的就直接截取等号后的结果进行显示或者再运算。
4
本次C++课程设计是非常贴近生活的,也非常实用的,计算器是我们生活中非常常见的产品,它的历史也已经很“悠久”了。以前都认为计算器应该是挺简单的,也是因为这个我选择了计算器的课程设计。但真是不做不知道,一做吓一跳,小小计算器却大有乾坤。不仅从它各个按键的排版,到实现各种计算的算法,都是很讲究的。
由于有记忆功能,所以在每一次按下按键时,只要产生了UpdateData(FALSE),就需要将Edit变量中的值更新到当前条记忆SHOW[0]中暂存。这样做的好处是在用户一个算式还没计算完时,去查看上一条记忆后还能再返回当前条继续计算,而不会由于Edit控件显示了上一条记忆而丢失当前正在计算的算式。
IDC_EDIT1
无
Button数字0~
Button数字9
IDC_BUTTON_0
IDC_BUTTON_9
0~
9
Button小数点
IDC_DOT
.
Button退格
IDC_BACKSPACE
<-
Button加法
IDC_ADD
+
Button减法
IDC_SUBTRACT
-
Button乘法
IDC_MULTIPLY
这个WorkR函数所解决的重点是对于多重括号的运算。我的算法的中心思想就是寻找括号:不论用户给的算式有多少的括号,我只寻找第一个封闭的括号,那么封闭括号中的算式就肯定是没有括号的,这个括号中的算式使用GetStr和GetResult函数计算出结果在替换到第一个括号的位置。这样就剥除了第一个括号,再重复寻找第一个封闭括号,一次类推。例如:
图7GetResult结果计算函数流程图
如图7所示此函数的作用是对通过图6函数分拣过的算式进行计算,通过图6函数分拣后,算式被分拣到a、b数组中。GetResult函数通过对a中数据进行b中算符运算,最终得到结果存放在数据数组a的a[0]中。
图8科学计算按钮响应函数
图8表示的是一类运算的流程图,由于类似所以由一个流程表现。设计科学计算都为单目运算,所以在按下科学运算相关运算时会先做一个类似于等号的操作:先判断是否为计算过的记忆式,在判断是否按下科学计算前是否按下过等于计算,如果都没有则表明Edit中是没有计算的算式,则需要计算一次,得到结果再进行科学计算。只要之前计算过,就可以直接截取等号后的结果进行科学运算。
针对用户的b类操作,我的对策就是在每次UPdateData(FALSE)后就将Edit变量m_strResult中的数据复制给当前条SHOW[0],不论用户何种操作,即使是使用了清空键(清空的响应函数UpdateData(FALSE)后面并没有添加SHOW[0]更新的语句,为了达到类似于误清空撤销的效果),也能使用点击“当前计算”找回刚才未算完的算式。
针对用户的a类操作,我的对策是在计算完当前算式后只是把它存在当前条SHOW[0]中暂时不用SHOW[0]去覆盖SHOW[1]。当用户开始下一次运算时才将SHOW[1]用SHOW[0]覆盖,将SHOW[0]解放出来存当前算式。于是我就设计了记忆标志位Remember,只要属于运算的按键按下,且计算成功了,记忆标志位Remember就会被置位(true)。此后只要按下例如数字、左括号这种可以开始新一次运算的按键,SHOW[0]中的数就会被推入SHOW[1],记录为上一条。
图3左右括号按键响应流程图
左括号和右括号的响应是有差异的,所以这里分别绘制了如图3的流程图。由于左括号是可以出现在一个算式的开头的,所它和数字按键类似,拥有添加和覆盖两种行为。当现在用户在键入一条算式,按下左括号,其对应的响应应该是添加左括号;当用户输入完毕按下了不论哪种运算,得到结果后,再按下左括号,说明下一次运算开始了,就需要对应覆盖的行为。而右括号是不能在左括号出现前出现的,所以在规则中添加限制。而且左括号前不能是数字和右括号,而右括号前不能是运算符和左括号,由于我的设计的算法的限制不能有括号的出现。
根据程序主流程图可以看出,我们需要一些能响应用户操作的响应函数来实现我们的计算器相应按键的功能。
图1程序主流程图
说明:所以流程图由深圳市亿图软件有限公司的流程图绘制软件(试用版)绘制,转存PDF后导出为图片加入到word中的,所以可能会打印效果不好,但确实为本人绘制。
图2数字按键与普通算符按键响应流程图
Sin
Button反正弦运算
IDC_arcSin
arcSin
Button余弦运算
IDC_Cos
Cos
Button反余弦运算
IDC_arcCos
arcCos
Button清空
IDC_BUTTON_CLEAR
清空
PictureControl
IDC_SEPARATOR
无
其中只有Edit控件关联了CString类型的值变量。
3
(1)等号运算
在计算器中最关键的功能就是等于的运算。在我的程序中进入等号响应函数后首先是判断Edit变量m_strResult中的存的是否是一个没有计算过的算式,即检查m_strResult中是否有等号,如果有则直接截取等号后的数值送给m_strResult,再通过UpdateData(FALSE)显示出来;如果是没有计算过的算式,就需要先检查算式的正确性,是否可以等于运算,如果不可以就弹出警告框,警告算式有错误。最核心的就是算式正确了,需要计算的步骤。
首先来说这个按键的排版,我做了好多次,一开始就是按顺序排放就是了,但在后面调试使用时就感觉很别扭,用着没有人家的计算器顺手。后来从市面上比较成熟的产品中看出些门道。一般数字键盘都是从左上方数字键“1”开始依次到“9”组成3X3的矩形,然后数字“0”是在数字“8”的下方,数字“0”的两侧可以放小数点和双零按键,然后由于加号运算和等号的使用频率较高,一般都会把这两个键做大一点,或者用其它颜色突出,然后使用频率越高的按键离数字键盘的位置就越近。这个也算是我的一点小发现把。
4)调试程序。
3
图9科学型用户界面
如图9所示为用户界面,初始时为科学计算型界面,显示所有的计算内容。当按下按键“普通计算”时,右边的科学计算就会被“折叠”消失,如图10所示。
图 10普通型用户界面
构成界面的控件及其属性如表1所示:
表1计算器对话框中各个控件及其属性表
对象
ID
Caption
Eidt编辑框
(7)界面为科学型和普通型,可在两界面间通过按钮转换。
2.
计算器属于桌面小程序,适合使用基于对话框的MFC应用程序设计实现。首先要思考的问题是:我的程序需要实现什么样的功能?需要哪些控件?需要哪些变量?需要哪些响应?
我们知道基于对话框的MFC应用程序的执行过程是:初始化、显示对话框,然后就开始跑消息循环列表,当我们在消息循环列表中获取到一个消息后,由相应的消息响应函数执行相应的操作。根据这个流程我们制定出计算器程序的程序框架主流程图,如下页图1所示。
IDC_SQRT
sqrt
Button平方运算
IDC_PINFANG
x^2
Buttone的x次方运算
IDC_E_X
e^x
Button自然对数运算
IDC_LN_X
ln x
Button阶乘运算
IDC_x_jiecheng
x!
Button 10为底的对数运算
IDC_LG_X
lg x
Button正弦运算
IDC_Sin
b.计算完一条算式开始计算下一条算式,这是刚计算按完的算式就成为了上一条,现在在计算的成为了当前计算,在这是他希望查看上一次的计算,而且他还要返回来继续当前计算;
c.不论在什么时候,他查看了一条完整的计算记录(有等号的完整计算),他又希望在现在查看的记录的基础上继续运算。
针对以上可能的情况我设定了一个两元素的数组SHOW[2]来存放,SHOW[0]存放当前条、SHOW[1]存放上一条。每次遇到UpdateData(FALSE)更新Edit时就意味着需要同步更新当前条SHOW[0]中的内容了,当按下等于或者科学计算算符是就意味着算式输入完毕。当等号响应函数中UpdateData(TRUE)之后就需要将算式存入当前条SHOW[0]中,等待计算成功得到结果后,通过相应的方式组装完整计算式存入当前条,如等号组装方式:SHOW[0] = SHOW[0] + "\r\n=" + m_strResult(其中\r\n是为了让等于及其之后的结果在Edit控件中换行显示);Sin运算的组装方式:SHOW[0] = "Sin(" + SHOW[0] + ")°\r\n=" + m_strResult。对于完整的计算式下次对它操作计算时只需截取等号后的结果就可以了。
计算3+(3+(1-2)*3+(3-2)/2)+(2+3)*5;
第一步:寻找第一个封闭括号,即(1-2)这个括号;
第二步:将原算式切开存成三段存储,即”3+(3+”、”1-2”、”*3+(3-2)/2)+(2+3)*5”;