《MFC编程及应用》课程设计报告
题目: 混合运算计算器
学号: 1003110131 姓名: 吴尧
指导老师: 杨均匀
时间: 2011年10月
评语:
一、实现效果
选题为题目六,但进行了一些变化。程序外观为一普通计
算器程序的外观,可以实现四则混合运算、进制转换的功能。
按下数字键、运算符号键、括号键,则在编辑框中显示输入的运算表达式;按下退格键(←),可以删除最后输入的一个字符;按下清除键(C),将清除所有输入内容;按下等号键,首先会进行表达式的检测,若检测得输入正确,则对表达式进行求值,并将结果输出在编辑框中。
点击此程序查看菜单下的进制转换菜单项,窗口将伸展出一进制转换的计算框。首先在组合框中选择需要转换的进制以及转换到什么进制,之后在输入框中输入要转换的数,点击计算按钮,即进行计算。计算之前,程序将对输入进行检测,若输入错误,例如输入数字并不为当前所选择的输入进制,则弹出消息框,提示错误;若正确,才进行计算。
二、设计步骤 1. 工程的建立
(1)建立基于对话框的应用程序,工程名设为
Calculator,
生成了CAboutDlg、CcalculatorApp、CcalculatorDlg三个类; (2)进行对话框的绘制,在其中添加了Button、RichEdit、StaticText、ComboBox等控件,并对控件的一些属性进行修改;
(3)进行菜单的编辑,在文件下有退出菜单,查看下有标准型、基本、进制转换菜单、帮助下有关于菜单;
(4)对关于对话框做了一些修改,改变关于对话框中图标的样式;
2. 新增变量与新增类
(1)Cal类,新增的普通类,主要用来负责检查表达式的正误、对表达式进行求值、与CcalculatorDlg类交换数据、返回计算结果值等方面,这个类十分关键,在程序的运行中起了十分重要的作用;
(2)CcalculatorDlg类中增加EditDisplay、EditInBox、EditOutBox三个CRichEditCtrl类型的变量,负责与对话框中的三个编辑框控件相关联;
(3)CcalculatorDlg类中新增rectLarge、rectSmall两个变量用来标记对话框伸缩情况下的大小,以实现对话框的伸缩效果;CalStr变量用来表示计算器中以输入的表达式;StrNum在进制转换中应用,用来表示输入的数字,并在转换过程中保存转换的结果;int_from与int_to两个变量,用来获取组合框选择的信息,并在进制转换中应用;
(4)在CcalculatorDlg中,还增添了一些成员函数,例如TwotoTen、EighttoTwo等函数用来进行进制的转换,docheck函数用来检测进制转换中输入是否正确,等等; 3.
需处理的消息及其代码
(1)首先需对对话框的初始化消息以及WM_CTLCOLOR消息进行响应,在响应函数中对窗口的外观、控件的字体以及其它一些项目做一些更改,OnInitDialog中增加代码如下:
//改变图标 HICON hIcon=AfxGetApp()->LoadIcon(IDI_ICON1);
SetIcon(hIcon,false); //设置组合框 ((CComboBox*)GetDlgItem(IDC_COMBO1))->AddString(L\"十进制\"); ((CComboBox*)GetDlgItem(IDC_COMBO1))->AddString(L\"二进制\"); ((CComboBox*)GetDlgItem(IDC_COMBO1))->AddString(L\"八进制\"); ((CComboBox*)GetDlgItem(IDC_COMBO2))->AddString(L\"十进制\"); ((CComboBox*)GetDlgItem(IDC_COMBO2))->AddString(L\"二进制\"); ((CComboBox*)GetDlgItem(IDC_COMBO2))->AddString(L\"八进制\"); ((CComboBox*)GetDlgItem(IDC_COMBO2))->SetCurSel(0); ((CComboBox*)GetDlgItem(IDC_COMBO1))->SetCurSel(0); //设置窗口伸缩效果 CRect rectsep; GetWindowRect(&rectLarge); GetDlgItem(IDC_SEP)->GetWindowRect(&rectsep); rectSmall=rectLarge; rectSmall.right=rectsep.left; SetWindowPos(NULL,0,0,rectSmall.Width(),rectSmall.Height(),SWP_NOMOVE|SWP_NOZORDER); //改变文本框字体与内容 CFont font; font.CreatePointFont(500,L\"宋体\"); EditDisplay.SetFont(&font); GetDlgItem(IDC_DISPLAY)->SetWindowText(L\"0\"); CFont old_font; old_font.CreatePointFont(350,L\"宋体\"); EditInBox.SetFont(&old_font); EditOutBox.SetFont(&old_font);
(2)菜单命令的响应函数,对菜单的按下进行处理,做出相应的反应,其中查看下的进制转换菜单项响应函数如下(基本菜单项原理相同,不再赘述):
void CcalculatorDlg::OnTrans() { // TODO: 在此添加命令处理程序代码// SetWindowPos(NULL,0,0,rectLarge.Width(),rectLarge.Height(),SWP_NOMOVE|SWP_NOZORDER); //窗口的伸缩 GetMenu()->GetSubMenu(1)->CheckMenuItem(2,MF_UNCHECKED|MF_BYPOSITION); GetMenu()->GetSubMenu(1)->CheckMenuItem(3,MF_CHECKED|MF_BYPOSITION); } //基本与进制转换菜单项前标记的转换
(3)数字键及运算符的按下消息。在消息响应代码中对CalStr变量进行更新,并在编辑框中进行显示,对于此消息响应函数,
各个按钮处理基本相同,举1数字键为例说明:
void CcalculatorDlg::OnBnClickedNum1() { // TODO: 在此添加控件通知处理程序代码 if(flagok) { CalStr=\"1\"; EditDisplay.SetWindowText(CalStr); //编辑框中显示 //光标置于最后,以使编辑框中最后输入的能够显示出来 EditDisplay.SetSel(CalStr.GetLength(),CalStr.GetLength()); EditDisplay.SetFocus(); flagok=false; } else { CalStr+=\"1\"; EditDisplay.SetWindowText(CalStr); EditDisplay.SetSel(CalStr.GetLength(),CalStr.GetLength()); EditDisplay.SetFocus(); } }
程序中,变量flagok用来表示是否完成了一次计算,若完成一次计算后,按下数字键,应对字符串等进行清零;若按下退格键,即调用CalStr的Left(CalStr.GetLength())函数,获得清除最后一个字符的效果;
(4)等号键的按下消息。在此消息响应函数中,主要将CalStr传递给一个Cal类的对象,并通过Cal类的成员函数,对此字符串进行检查与求值,若检查有错误,则通过检查函数返回值了解错误内容,并用MessageBox做出提示,因消息响应函数代码较长,在此不给出,下面具体来讲Cal类中对表达式字符串处理的一些思路:
① 表达式的检查部分,主要考虑四种情况:括号不匹配、
两个括号紧邻、两个运算符紧邻、数字与括号紧邻而缺少运算符;对于后三者的检查比较简单,仅需对字符串进行扫描并判断即可;对于括号不匹配的检查,主要采用栈的思路,通过扫描至左括号时入栈、遇到右括号时将相应的左括号弹出栈,以此来判断是否匹配;
②表达式的求值,也是应用栈的思想,通过将中缀表达式转化成后缀表达式,再对后缀表达式求值来进行;在本程序中,建立两个栈,一个是符号栈,一个为操作数栈,通过动态模拟中缀与后缀表达式的转换,来计算表达式的值;
(5)进制转化部分中,计算键按下消息;消息相应函数中,主要对组合框中所选进制进行判断,并通过之前建立的进制转换函数来进行进制转换;转换过程中值在StrNum变量中存储,计算完毕后将此值显示在输出编辑框中;
三、遇到的问题及解决办法
因为MFC的复杂性,以及学习中并未能完全掌握,在程序设计中确实遇到了很多的问题,在此举一些比较有代表性的作为例子:
1. 在应用RichEditControl2.0控件时,运行程序发现窗口无法生成,程序未能正常执行;开始以为是编写代码中出了问题,但不断地检查都未能找到错误;之后想到可能是因为RichEditControl2.0控件的问题导致程序无法正常运行,于是删除对话框中的所有此控件,发现程序恢复正常;这时考虑是不是使
用此控件时有什么要求,于是求助MSDN,发现其中有一句“必须首先调用 AfxInitRichEdit2 以加载 RichEdit 2.0 控件”;在对话框的构造函数中加入此语句,程序得以正常运行;
2. 本想此程序计算结果可以为浮点型,但是面临着将浮点型转换为CString类型的问题,使用强制转换、sprintf函数、stringstream流的方式处理,最终都会出现一些问题,上网去查也得不到好的结果,并且考虑到浮点运算的复杂性,于是退而求其次,程序的计算结果输出只能为整形;
四、体会与建议
经过一个月的MFC学习,又经历了自己独立开发MFC程序
这样一个过程,确实收获了不少,不仅对于MFC,对于程序的开发,乃至我个人的学习和生活,都有一些心得体会,下面就来谈一谈。
我是化工学院的学生,虽说没有通过上课这种形式对C++进行学习,但凭着多年来对编程的热爱,自己对C++早已有了一些研究,甚至可能比上过C++课的同学理解还要深。但是以前对于程序的应用,主要是在算法方面,高中时期参加信息学奥赛让我学到了许多算法的知识。但是,我感觉自己对于开发窗口程序,还是有着更多的兴趣。
于是,我选修了这一门课,希望能够对MFC有一些初步的认识,并且学会自己用C++开发一些简单的窗口应用程序。
当然,在这一段时间的学习中,我学到了很多,我了解了
MFC编程开发的一些机理,大致明白了一个MFC的程序是如何运行的;我也学会了如何进行简单的MFC开发,能够做出以上的一个非常简单的应用程序;另外,我还能够体会到一种思考问题的方式,因为编程本来就是一门逻辑性很强的学科,在编程的过程中总能够锻炼自己的逻辑思维能力,丰富自己看问题的角度和解决问题的方法;最重要的,我想是进一步培养了自己的耐心、细心、条理性,编程序过程中很容易出现许多问题,当遇到问题时不应该急躁,而应该静下心来,耐心地思考问题究竟出在什么地方、怎样解决问题,应该调理地分析,想想问题究竟出现在哪个环节,其实这才是最重要也是最应当学到的,这对于我们的学习和生活同样有着很重要的意义。
编程看似是一项很无聊的工作,但是投入进去,也能发现很多乐趣,发现我们可以学到很多东西。
当然,还要感谢杨均匀老师,辛辛苦苦地授课,耐心地教导,让我们在这门课中有许多宝贵的收获。
五、参考文献
1. B.Lippman , Josée Lajoie , Barbara E.Moo . C++ Primer中文第四版.人民邮电出版社,2006
2. 孙鑫,余安萍. VC++深入详解. 北京:电子工业出版社,2006
3. 侯俊杰. 深入浅出MFC
4. H.Cormen,E.Leiserson .算法导论,机械工业出版社
因篇幅问题不能全部显示,请点此查看更多更全内容