MFC简单计算器设计正文.docx
- 文档编号:12570922
- 上传时间:2023-04-20
- 格式:DOCX
- 页数:37
- 大小:432.45KB
MFC简单计算器设计正文.docx
《MFC简单计算器设计正文.docx》由会员分享,可在线阅读,更多相关《MFC简单计算器设计正文.docx(37页珍藏版)》请在冰豆网上搜索。
MFC简单计算器设计正文
实用计算器程序
1.基本功能描述
计算器是人们日常生活中非常实用的计算工具。
预期设计目标与实际计算器为标准,Windows10系统提供的计算器为范例进行设计。
实用计算器要实现单目运算和双目运算。
单目运算主要包括阶乘、正弦、余弦;双目运算主要包括加、减、乘、除、乘幂等。
计算器要能够对输入的各种数据进行处理,包括小数、整数、负数等数据进行操作。
实际过程中要能够对不同的数据灵活判断执行。
同时要能够对不满足运算符的操作数,提示出错信息以方便用户进行处理。
用户的修改包括清屏和退格。
程序设计的重点和难点在于:
第一,能够对于不同的操作数和操作符进行连续运算,运算过程中要有优先级的判断,根据优先级执行不同的运算顺序;第二,能够用一个编辑框实现运算表达式的显示和结果的输出。
编程环境采用VisualStudio2017提供的MFC建立对话框应用程序,设计界面要简单大方,并提供程序所有功能的接口。
2.设计思路
表1操作符优先级设计
优先级
操作符
1
阶乘、正弦、余弦
2
乘幂
3
乘、除
4
加、减
对对话框编辑框关联一个变量从中读取数据,按下数字键时对数据数组num[]进行更新,其中num[0]表示的是当前已经存储变量的个数。
由于算法设计为四层优先级,且单目运算的优先级最高。
当按下相应单目运算符,首先将当前数据数组的最后一个存储(防止按下Backspace退格发生错误),并将此位数据执行运算后重新赋值。
但按下双目运算符相应按键后,将计数num[0]++,同时将运算符的类型和位置记录。
当按下等于之前,这样就将一个单目双目混合的运算表达式转化为双目运算。
如果没有按下等号键,则继续执行循环。
在按下等号按钮之后,按照先乘幂、再乘除、后加减的运算顺序执行运算,将最后结果保存并显示。
(在实际的计算器中,执行完运算之后,按下运算符的操作键,最终结果将按照左操作数的形式出现,故需要保存变量。
)如果用户没有结束程序,在运行初始化程序,进行下一次运算,否则直接退出。
图1程序流程图
3.软件设计
3.1设计步骤
1)创建基于对话框的程序
利用AppWizard建立应用程序框架,创建一个基于对话框的MFC工程,命名为“fengwanjincalculator”,如图2所示。
在图3显示的应用程序类型中选择基于对话框。
创建成功后,系统自动生成相应程序文件。
图2创建MFC工程图
图3应用程序类型选择图
2)定义成员变量
添加相应变量和标志位,以方便程序的编写,主要变量如表2所示:
表2成员变量表
变量名
变量类型
变量作用
mystr
CString
编辑框关联变量
m_editFont
CFont
设置编辑框字体
num
float
存储操作数
flagdian
bool
点号标志位
flagdengyu
bool
等号标志位
flagerror
bool
错误标志位
Jiajian
int
存储加减运算符的位置
4)添加事件处理程序
MFC应用程序是通过消息响应来进行各项操作的,必须在对话类中加入消息处理函数来处理这些事件。
当点击相应控件,在进入WinMain函数之前,每个可以响应消息的MFC类都生成了一个消息映射表,程序运行时通过查询该表判断是否需要响应某条消息。
在相应控件单击右键,弹出图4,选择添加事件处理程序,在图5的事件处理程序向导中选择fengwanjincalculatorDlg类,消息类型选择为BN_CLICKED,即左键单击。
图4添加事件处理程序
图5选择添加事件处理程序类型
在完成上述操作后MFC使用ClassWizard帮助实现消息映射,它在源码中添加一些消息映射的内容,并声明和实现消息处理函数。
首先,在类的定义(头文件)里,它增加了消息处理函数声明,并添加一行声明消息映射的宏DECLARE_MESSAGE_MAP。
在类的实现(实现文件)里,实现消息处理函数,并使用IMPLEMENT_MESSAGE_MAP宏实现消息映射。
BEGIN_MESSAGE_MAP
******
END_MESSAGE_MAP
3.2界面设计
图5向对话框添加控件
在项目的资源视图中找到位于Dialog下的对话框,如图4所示。
添加相应控件,完成用户界面设计。
图6用户界面设计
其中编辑框行为下Multiline属性设置为True,作为多行编辑框。
第一行显示算式,第二行结果。
整体上将控件分为四组,数值控件区NUM,加减乘除一般运算控件区NORMAL,阶乘、乘幂、正余弦科学运算控件区SCIENCE以及清零退格控件。
设计完成后的界面如图7所示。
图7用户界面
设计的界面中只有编辑框关联Cstring类型变量mystr。
其余控件关联相应的消息处理函数。
3.3关键功能的实现
程序主要分为数值、单目运算、双目运算、清除等。
1)数值控件消息处理函数
voidCfengwanjincalculatorDlg:
:
OnBnClickedButton1()
{
shuzihanshu(L'1',1);
}
考虑到0~9数字的处理函数有很大的相似处,所以都采用调用shuzhihanshu函数的方法执行。
shuzhihanshu包含两个参数,分别是数值对应字符和相应数值。
其具体实现如下:
voidCfengwanjincalculatorDlg:
:
shuzihanshu(charshuzi,intshuzhi)//0~9对应函数
{
UpdateData(TRUE);
if(flagdengyu)
{
OnBnClickedButtonClear();
}
flaglast=0;
mystr+=shuzi;
data=shuzhi;
changevalue();
UpdateData(FALSE);
}
首先,判断再点击数值控件之前是否按下等号键,如果按下执行OnBnClickedButtonClear(),即执行清除函数,然后将单击的数值显示在编辑框中。
如果之前没有单击等号,则直接将数值添加到显示字符串的最后,通过UpdateData(FALSE)更新编辑框控件。
同时需要将数值传递给data,通过changevalue()函数改变数值数组中的数值。
2)双目运算消息处理函数
voidCfengwanjincalculatorDlg:
:
OnBnClickedButtonJia()//加
{
sincos();
if((flaglast==0)||(flaglast==jiecheng))
{
shuangmusuanfu(L'+',jia);
flaglast=jia;
jiajian[0]++;
jiajian[jiajian[0]]=1;
}
}
双目运算首先设置相应标志和参数的改变,其主要的函数体部分由shuangmusuanfu函数概括,其中jia参量为用枚举定义的一个常量。
枚举定义如下:
enumsuit{jia=1,jian,cheng,chu,jiecheng,zhishu,Sin,Cos};
shuangmusuanfu中函数实现部分:
函数体中首先对是否按下等号是否有表达式错误进行判断,如果相应标志为1,则转到相应处理函数,否则将算符存储,数值计数器num[0]加一。
3)清除函数
voidCfengwanjincalculatorDlg:
:
OnBnClickedButtonClear()
{
UpdateData(TRUE);
mystr=L"";
flagdian=0;
beishu=1;
flagerror=0;
data=0;
flagdengyu=0;
for(inti=0;i<10;i++)
{
jiajian[i]=0;
chengchu[i]=0;
mizhi[i]=0;
num[i]=0;
nextdata[i]=0;
}
num[0]=1;
flaglast=0;
UpdateData(FALSE);
}
清除函数中主要讲各个参量重新初始化,同时通过UpdateData(FALSE)更新编辑框控件。
4.结论与心得体会
1、Windows编程中可能会遇到可能会遇到各种编译问题,例如编译环境的设置,具体函数的调用。
同时Windows为程序员提供了大量的库函数,在具体实践的过程中,要充分利用书籍和网络查阅相关函数和环境设置,减轻编程负担。
2、考虑到编程的难度,首先编写了未设置优先级的表达式运算,后又通过在原先程序的基础上,编写了设置优先级的程序。
由于两种方式在算法设计上有很大不同,导致了程序改进的困难。
3、由于在编程思想方面并没有参照网上的先例,也没有采取堆栈的方式进行优先级的运算,在具体编程的过程中遇到了很多细节问题。
所以在日后的编程中要注意,算法与数据结构的结合。
4、相较于传统的C++编程,MFC的编程不仅要考虑算法和数据结构的问题,还需要考虑环境、用户界面的美观便捷等问题,编程的难度更大,出现的问题也更多,在编程的过程中渐渐提高了自己的耐性和对于新事物的应用能力。
5、从本次编程的结果来看,此次编程需要提高的方面还很多,人机交互界面的设计、程序算法的统一性、可读性都有待提高。
在程序的设计过程中主要参考了Windows10参做系统自带的计算器,交互界面如图8所示:
图8Windows10计算器
仅从界面看,差距还很大。
但是任何一个程序都不可能是完美的,这款计算器在调试的过程中也发现了一些bug,所以在日后更加重要的学习和工作中的编程过程中,要注意程序的调试和检查,完善任何一个优秀程序都是需要细致耐心的打磨。
5.思考题
1、程序如何实现小数的显示和运算?
首先,数值数组采用float类型,可以实现整形和浮点型的统一运算。
在读取数值的过程中要加入小数点的判断,如果出现了小数点,则在之后读取的每一个数值需要将相应的倍数每次除以10乘以读出的数值与原数值相加得到。
例如changevalue函数:
voidCfengwanjincalculatorDlg:
:
changevalue()
{
if(!
flagdian)
{
num[(int)num[0]]=data+num[(int)num[0]]*10;
}
else
{
beishu/=10;
num[(int)num[0]]=num[(int)num[0]]+data*beishu;
}
}
对于例如阶乘等只能对于整形进行运算的运算符或函数,首先对数值取证判断其是否与原数据相等,如果相等则可以进行相应运算。
如果不同,则通过AfxMessageBox函数弹出错误提示,错误窗口如图9所示:
图9错误提示窗口
2、描述等号对应的消息处理函数中需要问题及相应实现代码?
点击等号控件,则首先要进行表达式是否正确的判断(本次程序编写过程中,运算符操作的合法性检查放在了每个运算符的函数中,故在等号的消息处理函数中不需要再添加),将结果计算得出并显示在窗口上,同时设置相应的标志。
具体代码如下:
voidCfengwanjincalculatorDlg:
:
OnBnClickedButtonDeng()//等于
{
sincos();
CStringtemp;
calculator();
if(!
flagerror)
{
temp.Format(_T("%g"),num[1]);
mystr+=L"\r\n";
mystr+=temp;
}
flagdian=0;
beishu=1;
flagerror=0;
flagdengyu=1;
UpdateData(FALSE);
}
在实现过程中,首先通过calculator()执行相应运算得到结果,发生没有错误则将结果显示在编辑框中。
同时设置标志位,标志等号消息处理函数已经运算完。
6、附录
6.1调试报告
程序编译运行过程中主要遇到了类型转换问题、函数调用或执行问题、结果错误问题等。
1、类型转换问题
此类问题错误提示比较明确,更改也比较容易,只需要双击错误提示,转到相应的出错代码,进行相应处理即可。
例如,num数组设置为float类型,而为了减少变量的个数,采用num数组的第一位作为数组中数值个数的计数器。
故采用num[num[0]]表示最后一位数值,程序报错,提示只能为整数下标。
改为强制类型转换即可——num[(int)num[0]]。
2、函数调用或执行问题
此类问题一般在编译过程中并不报错或者不能给出有效的错误提示,导致发现的困难性。
例如,在CfengwanjincalculatorDlg类自声明了一个函数,而在相应的.cpp文件中忘记相应函数实现的编写,编译运行过程中仅提示找不到相应的.exe文件。
通过pause函数等暂停函数到某一点,找到错误的区间解决问题。
2、结果错误问题
此类问题在本次编程过程中遇到的情况较多,采用的自己模拟程序执行流程发现问题,如果不能通过这种方式发现,则通过设置断点,单步执行观察变量在每一步中的变化,并于自己的设想相比较发现问题。
6.2测试结果
1、键入表达式125+6*5-8!
+7^3点击等号得到表达式的结果,与实际相一致,如图10所示。
图10键入数值并执行运算
2、点击加号后可以继续执行运算。
图11点击加号继续运算
3、按下数值9,清屏屏显示数值9
图12按下数值9
4、清屏
图13清屏
5、错误提示
图14错误提示
6.3关键源代码
1、fengwanjincalculatorDlg.h文件中自定义变量和函数的相应声明:
public:
intjiajian[10];//第一位为加减算符个数,后面几位的绝对值为位置,+为正,-为负
intchengchu[10];//第一位为乘除算符个数,后面几位的绝对值为位置,+为正,-为负
intmizhi[10];//第一位为乘幂算符个数,后面几位的绝对值为位置,+为正,-为负
floatnum[10];//操作数数值数组
intflaglast;//判断表达式最后一位为算符或者数值0为数值,1~8为相应算符
floatnextdata[10];
CStringmystr;//编辑框字符串
CFontm_editFont;//编辑框字体
boolflagdian;//0为没加点1为加了点
floatbeishu;//倍数
boolflagerror;//0未发生错误1发生错误
intdata;//按键数值
boolflagdengyu;//是否按下=
voidcalculator();//计算函数
voidchangevalue();//改变操作数
voidshuangmusuanfu(char,int);//双目算符对应函数
voidshuzihanshu(char,int);//数字对应函数
voidsincos();
afx_msgvoidOnBnClickedButton1();
afx_msgvoidOnBnClickedButton2();
afx_msgvoidOnBnClickedButton3();
afx_msgvoidOnBnClickedButton4();
afx_msgvoidOnBnClickedButton5();
afx_msgvoidOnBnClickedButton6();
afx_msgvoidOnBnClickedButton7();
afx_msgvoidOnBnClickedButton8();
afx_msgvoidOnBnClickedButton9();
afx_msgvoidOnBnClickedButtonDian();
afx_msgvoidOnBnClickedButton0();
afx_msgvoidOnBnClickedButtonClear();
afx_msgvoidOnBnClickedButtonBackspace();
afx_msgvoidOnBnClickedButtonJia();
afx_msgvoidOnBnClickedButtonDeng();
afx_msgvoidOnBnClickedButtonJian();
afx_msgvoidOnBnClickedButtonCheng();
afx_msgvoidOnBnClickedButtonChu();
afx_msgvoidOnBnClickedButtonZhishu();
afx_msgvoidOnBnClickedButtonJiecheng();
afx_msgvoidOnBnClickedButtonSin();
afx_msgvoidOnBnClickedButtonCos();
2、在fengwanjincalculatorDlg.cpp文件中声明的枚举类型
enumsuit{jia=1,jian,cheng,chu,jiecheng,zhishu,Sin,Cos};
3、CfengwanjincalculatorDlg构造函数中的初始化
CfengwanjincalculatorDlg:
:
CfengwanjincalculatorDlg(CWnd*pParent/*=NULL*/)
:
CDialog(IDD_FENGWANJINCALCULATOR_DIALOG,pParent)
mystr(_T(""))
{
m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);
//自添加
flagdian=0;
beishu=1;
flagerror=0;
data=0;
flagdengyu=0;
for(inti=0;i<10;i++)
{
jiajian[i]=0;
chengchu[i]=0;
mizhi[i]=0;
num[i]=0;
nextdata[i]=0;
}
num[0]=1;
flaglast=0;
}
4、CfengwanjincalculatorDlg:
:
OnInitDialog()设置编辑框字体
m_editFont.CreatePointFont(180,"宋体");
CEdit*m_Edit=(CEdit*)GetDlgItem(IDC_EDIT);
m_Edit->SetFont(&m_editFont);//设置新字体
5、清屏函数
voidCfengwanjincalculatorDlg:
:
OnBnClickedButtonClear()
{
//TODO:
在此添加控件通知处理程序代码
UpdateData(TRUE);
mystr=L"";
flagdian=0;
beishu=1;
flagerror=0;
data=0;
flagdengyu=0;
for(inti=0;i<10;i++)
{
jiajian[i]=0;
chengchu[i]=0;
mizhi[i]=0;
num[i]=0;
nextdata[i]=0;
}
num[0]=1;
flaglast=0;
UpdateData(FALSE);
}
5、退格函数
voidCfengwanjincalculatorDlg:
:
OnBnClickedButtonBackspace()
{
//TODO:
在此添加控件通知处理程序代码
UpdateData(TRUE);
//移除最右边一个字符
if(!
mystr.IsEmpty())
{
chartemp;
temp=mystr[mystr.GetLength()-1];
if(temp>=48&&temp<=57)
{
if(!
flagdian)
{
num[(int)num[0]]=(num[(int)num[0]]-(temp-48))/10;
}
else
{
num[(int)num[0]]=num[(int)num[0]]-(temp-48)*beishu;
beishu*=10;
}
mystr=mystr.Left(mystr.GetLength()-1);
}
elseif(temp=='.')
{
flagdian=0;
mystr=mystr.Left(mystr.GetLength()-1);
}
else
{
num[0]--;
switch(temp)
{
case43:
case45:
jiajian[jiajian[0]]=0;
jiajian[0]--;
mystr=mystr.Left(mystr.GetLength()-1);
break;
case42:
case47:
chengchu[chengchu[0]]=0;
chengchu[0]--;
mystr=mystr.Left(mystr.GetLength()-1);
break;
case33:
num[0]++;
num[(int)num[0]]=nextdata[2*(int)nextdata[0]];
nextdata[2*(int)nextdata[0]-1]=0;
nextdata[0]--;
mystr=mystr.Left(mystr.GetLength()-1);
break;
case94:
mizhi[mizhi[0]]=0;
mizhi[0]--;
mystr=mystr.Left(mystr.GetLength()-1);
break;
case110:
num[0]++;
num[(int)num[0]]=nextdata[2*(int)nextdata[0]];
nextdata[2*(int)nextdata[0]-1
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- MFC 简单 计算器 设计 正文