西北农林科技大学信息工程学院
面向对象程序设计实习报告
题 目:简易计算器的设计与实现
目 录
一、综合训练目的与要求.............................................................................................. 2
二、综合训练任务.......................................................................................................... 3
(一)综合任务...................................................................................................... 3
(二)个人任务:................................................................................................... 3
三、总体设计................................................................................................................. 3
(一)功能模块图................................................................................................... 3
(二)功能实现...................................................................................................... 3
四、详细设计说明.......................................................................................................... 5
(一)主窗口控制类............................................................................................... 5
(二)实现说明:................................................................................................... 6
五、调试与测试............................................................................................................. 9
(一)使用说明书................................................................................................... 9
(二)调试结果...................................................................................................... 9
六、实习日志................................................................................................................ 11
七、实习总结............................................................................................................... 14
八、附录:核心代码清单............................................................................................. 14
stack类................................................................................................................... 14
calculatorWindow类............................................................................................... 15
calculatorWindow.cpp............................................................................................. 17
ButtonPress.cpp...................................................................................................... 19
Calculator.cpp......................................................................................................... 21
一、综合训练目的与要求
《面向对象程序设计》课程设计是实践性教学环节之一,是《面向对象程序设计》课程的辅助教学课程。
该课程设计要求学生综合运用在《面向对象程序设计》课程中学到的面向对象技术与实际编程相结合,独立完成一项较为完整、并具有一定实际功能的课程设计任务,同时加深学生对面向对象和C++编程技术的理解和掌握,培养实际的应用程序开发能力。在课程设计过程中,使学生养成良好的程序设计风格,并掌握C++应用程序的设计开发过程和编程方法、测试方法。培养学生使用MFC或者QT设计程序,使学生学会使用他们去开发软件。
二、综合训练任务
(一)综合任务
设计一个计算器,要求如下:
1、实现最大输入十进制数字的四则运算(有正负数区分)。
2、实现三角函数和反三角函数的计算、开方、次幂、求对数、取余等。
3、设置输入数值的最大长度,溢出报警。
4、除法和乘法结果用科学计数法并保留到小数点后2位 。
(二)个人任务:
1、学习qt使用,学习qt中信号和槽机制。
2、在qt中实现代码与界面的连接。
三、总体设计
(一)功能模块图
功能设计如图1,分为来个部分进制转换和表达式计算。
(二)功能实现
1、程序设计过程中分为两个模块,第一模块为计算器界面的类CalculatorWindow,如图2,包括各个按钮的声明以及函数运算的实现,包括了俩个栈,分别为运算符栈和数字栈,以及各个实现函数;第二个为stack类,如下图3包括了各个判断栈的情况的函数。具体的UML视图如下所示:
2、此程序设计主要运用了栈,利用栈后进先出的原理,建立两个栈,数字栈和运算符栈,先将数据和运算符分别压入这两个栈,判断栈内和栈外运算符的优先级,依据运算符的优先级判断是应再次压入运算符,还是将数据和运算符弹出栈,在栈外进行运算,再将所得的结果压入栈,继续进行与计算,直至运算结束。
3、建立工程文件视图如图4:
图4 文件工程视图
四、详细设计说明
(一)主窗口控制类
1、界面总共有26个按钮,包括10个数字键按钮、一个小数点按钮、一个等号按钮、12个运算符按钮、一个清除按钮、一个退格键、以及俩个括号按键,按照简洁化布局风格,第一个元素为operateEdit文本框,后面采用四个面板设计firstLayout、secondLayout、thirdLayout、fourthtLayout,具体界面设计如下图5所示:
图5 计算器界面
2、各个按钮、按钮功能以及所使用函数说明,如表1。
表 1按钮功能表
(二)实现说明:
1、除进制转换按钮、清除键、退格键和等号按钮外,其他按键都只是简单的输入文本信息,具体函数如下:
数字键按键响应事件函数:
操作符按键响应事件:
2、进制转换函按钮调用了进制转换函数,由于八进制和二进制没有特殊字符,转换函数一样,具体的函数算法如下:
十进制到十六进制的转换由于牵涉到字母,故比较麻烦,具体实现如下图6:
图6十进制到十六进制转换流程图
3、等号的实现是程序中最精华的部分,采用了栈的思想,主要运用了栈,利用栈后进先出的原理,建立两个栈,数字栈和运算符栈,先将数据和运算符分别压入这两个栈,判断栈内和栈外运算符的优先级,依据运算符的优先级判断是应再次压入运算符,还是将数据和运算符弹出栈,在栈外进行运算,再将所得的结果压入栈,继续进行与计算,直至按等号运算结束。流程图7如下:
图 7计算表达式值得流程图
在此过程中涉及到优先级的排序问题:
(1)每个用函数或倒数的都是字表达式内层向外层的方向输出(括号的优先级最大)
(2)三角函数的站内优先级和栈外优先级问题:
(3)采用的优先级时栈外比栈内的大,3个三角函数运算符的栈内优先级相同、栈外优先级也相同;三角函数的优先级比加减法大,比乘除法大,比括号小;三角函数与倒数;三角函数的栈外优先级要低于倒数的栈内优先级;三角函数的栈内优先级要高于倒数的栈外优先级
(4)倒数的优先级 倒数的栈外优先级要低于栈内优先级
(5)开二次方,栈外优先级低于栈内优先级,开方函数的栈内优先级高于加、减、乘、除、以及其他函数的栈外优先级,栈外优先级高于加、减、乘、除栈内优先级,栈外优先级低于其他几种函数的栈内优先级
综合考虑得出的优先级排序如下表2:
表 2 优先级排序
4、按键响应事件的流程图8如下,只有在opreate为1、opreated为0时才可以键入运算符,以达到运算符不能连续输入,输入数字时,先opreate置为0,输入完后置opreated = 1等待运算符的输入。
图8 按键响应流程图
五、调试与测试
(一)使用说明书
(1)此计算器采用先输入表达式,再计算结果的方式。
(2)进行三角函数的计算和开方、平方的计算时,先输入数字,再输入三角函数运算符和开方、平方运算符,注意为了变成方便编程,sin使用S代替,cos使用C代替,tan使用T代替,sqrt使用Q代替,pow使用W代替。如sin1+cos2+tan3显示为1S+2C+3T。
(3)其他使用和其他计算器的使用类似。
(4)如果结果出现“####”,则表达式有问题,请注意输入!
(二)调试结果
2*(3+4)的运算:
输入2*(3+4)显示如下图9
图9
按下等号显示结果如下图10所示:
图10
12的二进制计算:
输入12显示如图11所示
图11
按下二进制运算符,显示结果如图12所示:
图12
六、实习日志
20##-1-6
今天的任务主要是写实习计划书以及确定项目要实现那些功能,并且借鉴一下前面的师兄师姐们的作品,查了查相关的资料,下载相关软件,并且简单学习他们的使用方法。我们的项目决定要用qt来做界面,千辛万苦找到了下载地址,下载qt软件,安装后不能使用,后来查阅相关资料后知道需要提前minGW,在多次校正后,软件终于可以使用了。下面是下载相关软件的地址:minGW的下载地址http://sourceforge.net/projects/mingw/postdownload?source=dlpQT的下载地址http://qt-project.org/downloads在下午的时候,找了相关的项目来参考参考了一下,确定计算器要实现的功能以及要分成哪些模块。这些是一些参考项目。实践论文http://www.docin.com/p-664645791.html论文: http://blog.csdn.net/firecityplans/article/details/7831973
20##-1-7
我们对计算器的功能模块进行的划分,完成了模块设计图。为了编程实践的方便,我们又完成了流程图。由于电脑上的Qt一直没能安装成功,所以,我就主要考虑编程的过程,尝试先用Code: Blocks实现计算器的功能。在这个过程中,我发现对用栈实现表达式求解的过程需要的数据结构知识已经忘了很多,不过经过查资料和分析自己明白了过程,明天就是将程序继续编完。我还看了关于Qt的使用,发现里面的类和方法都很陌生而且用法感觉有点儿奇怪,应该是还不了解的原因。觉得目前先完成一件事,就是先完成控制台程序,然后再用Qt完成界面设计今天主要是根据所确定的功能的确定我们的项目都需要包含哪些函数,以及采用哪种方式去实现,我们决定用栈来实现,并且做了流程图。初步设计了界面。对QT的使用还不是很好,正在初步的学习中,他和其他的界面设计软件不同,搞得我满头雾水。不过我觉得摸索这些软件的是使用是一件很开心的事。遇到的问题:
1、使用qt界面设计和文件中源代码并不一致,怎么进行事件交互?使用了信号和槽机制,但如何实现呢?是什么原理?
2、使用qt进行设计界面时,如何能够有条理的管理已有控件?qrc文件又是什么东西?有什么作用?Qt中的qrc文件是一个xml格式的资源配置文件,与应用程序关联的应用程序由 .qrc 文件来指定,它用XML记录硬盘上的文件和对应的随意指定的资源名称,应用程序通过资源名称来访问资源。
20##-1-8
今天的主要任务是学习qt的使用方法,还是没怎么搞明白界面和代码的联系,感觉他和我之前学习的java设计界面、C#中的WPF大不一样,很难驾驭。可能是我还没有学习到他的精华所在吧。感觉那个样式表不是很好用,在设计中可以佷容易实现,但是要写代码实现,又不是很好做。继续学习中!
20##-1-9
今天的主要任务是实现简单的一些功能,实现算法与界面的互联,在一天的努力下,终于明白了信号和槽机制的使用,实现了简单的加减乘除。在界面的设计过程中,捉摸了老半天,才知道怎么做出绚丽的界面,样式表的使用以及样式表的语法,很多都还不会再进一步的琢磨中。感觉我们的进度还是太慢,一周的实习也即将快要结束了,但我们的还没有实现,继续奋斗中!
20##-1-10
今天怀着忐忑的心来编程序,结果当开始编的时候感觉c++已经忘了很多。只能是一边复习,一边编写。下午老师介绍了mfc和Qt的相关知识,我觉得其实这些东西真的需要自己去试着用才能掌握,不是一朝一夕的事,当然学习这些需要好的习惯,希望通过这次实习,我能克服自己不想研究陌生东西这个心理障碍。实习即将结束,我感觉今天的收获不是很多,效率有点儿低,时间越来越紧张了,我们的任务还是很重,我们必须加把劲了!
20##-1-13
今天还是在进一步编写代码中,感觉好多东西都忘的差不多了,只能边学习边编写,早上实现了进制转换函数,有点小小的成就感。感觉qt还是不好用,在编写代码的时候,有时候函数明明出错了,可程序还是可以运行,也搞不懂是什么原因,后来只能新建工程,再拷贝了。还有感觉我们的代码容错性太差了,我们只是考虑了正常情况的运行,还要努力考虑到各种异常情况,加强程序的健壮性。下午还是在进一步的编写代码,感觉时间有点紧张,而且加上考试,所以有点忐忑不安,好多功能还没有实现。对实习的时间安排极度不满,C++都学习一年了,忘的也差不多了,再加上考试,总觉得自己很难静下心来,好好编写。强烈建议学习能够改变一下实习时间,放在这个点上,实习做不好,考试考不好!为了后来的学弟学妹们,我要强烈说出我的不满!
20##-1-14
先说说我们的进度吧,我的队友在code blocks中已经可以实现计算器的一些基本功能,由我来实现qt界面与代码的结合,现在计算器基本可以运行了,正常情况下基本可以计算了,就是三角函数以及开方、平方计算还没有实现,不过这个应该很容易实现,因为基本框架已经搭建好了,今天还是再进一步调编写代码中,预计今天可以实现代码,后面就是再进一步的完善。接下来还有一个问题需要去解决,那就是如何在qt中保存exe文件,查了一下相关资料,好像不是那么容易实现,现在先把代码完善了再说吧!
20##-1-15
就说实话吧,今天由于要考试,整个一天也没怎么看。
20##-1-16
时间过得真快,两周的实习即将结束,我们的程序也做的差不多了,由于考试忙,还没怎么完善,今天继续完善以及写报告、做PPT。感觉实习时间安排的相当紧张,我们必须加把劲。今天继续把代码完善了,实现了十进制到十六进制的转换、实现了对输入的一些限制,如不能连续输入多个运算符、在进行第二次输入时,自动更新而不用去按清除键、退格键只有在输入时能够退格,对输出结果不响应。但还有好多需要去完善,我们会努力的。
七、实习总结
当时和队友选题的时候本来打算做数独游戏,后来班长说有人做了,我们只能放弃了,后来决定做计算器。其实在假期的时候做过一个小计算器,那时候是用C#语言写的,函数实现只是用了简单的加减乘除,没有实现优先级。
由于要用C++做,体现面向对象的思想,而现在已经距离C++学习有一年多了,C++基本语法都差不多忘记了,刚开始做的时候感觉一团乱,都不知道如何实现,和队友看完题目要求后,开始分析题目,我们决定采用栈的思想来实现,采用qt来设计界面,确定好方向后,我们开始分工,队友负责在codebooks来实现,我负责在qt中来实现。
记得当时学习C++的时候只是学习了基本语法,只会编写一些简单的程序,老师讲MFC也只是大概提了提,连最基本的用法都不会,更别说要做软件了。Qt也是第一次接触。安装qt就花了不少时间,打开qt只会在界面中设计,但并不懂得如何把代码和界面关联起来。后来通过简单的学习才知道qt中的精华部分是使用信号和槽机制。在设计界面中,对样式表的使用不是很明白,后来采用纯代码写的,在两个周的努力下,我们的程序终于可以运行了。最后两天对程序进行了完善,对用户输入进行了一些简单的限制,保证了程序的健壮性!但还是存在很多问题,估计实习期间可能没办法全部解决,我们会利用以后的时间尽量去完善的。
在此次实习中,我的收获也不少,下面我具体说说我的收获吧!
1、在以前的C++实习中,只是会编写一些简单的程序,并不懂得面向对象的思想体现在哪里,通过此次实习,使我对面向对象的概念有了更加深刻的理解。类的封装,使得程序更加清晰明了,简单易读。
2、学习使用新的软件设计软件——qt,开始时觉得qt很难掌握,界面和代码不容易结合在一起,虽说对他的学习并不是很深,只是会简单的使用,但学习使用一个新的东西的感觉还是很不错的。
3、此次实习是我第一次和同学合作做程序,团队协作是一个很重要的能力,通过此次实习,使我感受到了团队合作的快乐,以及让我学会如何和别人分工合作。总之,这次的合作还不错,分工明确,而又不脱离组织。是一次很值得记忆的实习。
4、说实话,虽然编程语言学了那么久了,还是很怕编代码,但通过此次实习,我真正的体会到了编程的快乐,至少我不会再害怕编程,拿到一个大的工程,学会冷静去分析。程序出错也不会再像以前那样,讨厌调试,学会了冷静分析代码中的错误。
虽然说程序已经基本可以运行了,但还是存在很多问题,下面我具体说说存在那些问题:
1、有些设计并不是很合理,比如三角函数、开方和平方的计算,使用并不是很友好,但是考虑到整体性,舍弃了对这部分的完美!
2、在操作中,对输入表达式的顺序并未做规定,也就是说怎么输入都可以,但在表达式不正确时,统一做异常处理,显示“####”。对用户输入还要做很多的限制,这块实现的并不是很好,有待完善。
总之,此次实习是一个新的开始,而不是结束!最后,感谢队友的帮助和配合,感谢老师的耐心指导!
八、附录:核心代码清单
stack类
#ifndef STACK_H
#define STACK_H
const int max_len = 20;//栈的最大容量
class stack
{
private:
char s[max_len];//栈的内容保存在数组中
int top;//栈顶指示器,栈空时为-1
float n[max_len];
public:
stack();
~stack();
int getTop();
void clear();
void push(char c);
void push(float f);
char pop(char c);
float pop(int f);
bool empty();
bool full();
char remove(char c);
float remove(int f);
};
calculatorWindow类
#endif // STACK_H
#ifndef JISUANQI_H
#define JISUANQI_H
#endif // JISUANQI_H
#ifndef CALCULATOR_H
#define CALCULATOR_H //对calculator.h头文件的声明
#include<QWidget>//包含主窗体类
#include<QPushButton>//包含按键类
#include<QVBoxLayout>//包含垂直布局器类
#include<QHBoxLayout>//包含水平布局器类
#include<QLineEdit>//包含显示框类
#include "stack.h"
using namespace std;
class calculatorWindow : public QWidget//计算器继承自主窗体类
{
Q_OBJECT //必须加上这句,如果要调用信号,槽函数的操作的话
public:
calculatorWindow(); //计算器类的构造函数
~calculatorWindow(); //计算器类的析构函数
public slots: //定义各个按键按下后对应操作处理的槽函数
long int changeHexadecimal(int num,int power);
void numButtonPress(char num);//按数字响应事件
void zeroButtonPress();//调用numButtonPress()函数
void equButtonPress();
void calculate();//普通计算
void hexChange(int num); //进制转换函数
bool operatorCompare(char stackOut,char stackIn);
void partCalculate(char oper);
void abortOperation(); //异常处理函数
private:
QLineEdit *operateEdit;//声明显示框
QPushButton *zeroButton;//声明数字按键¹
QPushButton *decimalButton;//小数点按钮
QPushButton *clearButton;
QPushButton *backspaceButton;
//声明运算符按键
QPushButton *addButton;
QPushButton *sinButton;
QPushButton *cosButton;
QPushButton *tanButton;
QPushButton *sqrtButton;
QPushButton *powButton;
QPushButton *equButton;
QPushButton *binaryButton;
QPushButton *octButton;
QPushButton *hexButton;
QPushButton *rightPerButton;
QPushButton *leftPerButton;
//声明水平布局器,该布局器主要对24个按键进行布局
QHBoxLayout *firstLayout;
QHBoxLayout *secondLayout;
QHBoxLayout *thirdLayout;
QHBoxLayout *fourthLayout;
QVBoxLayout *mainLayout;//声明垂直布局器,该布局器主要对主窗体上面的空间进行排布
QString input;//计算器中要输入的代数表达式
stack numStack;
stack operatorStack;
string str ;
};
#endif// CALCULATOR_H
calculatorWindow.cpp
#include "calculatorWindow.h"
#include "calculator.h"
using namespace std;
calculatorWindow::calculatorWindow()
{
this->setWindowTitle(tr("Calculator"));//设置窗体标题为Calculator
//calc = new calculators();
//按钮
operateEdit = new QLineEdit(this);
operateEdit->setReadOnly(true);
operateEdit->setText(tr("0"));
operateEdit->setAlignment(Qt::AlignRight);
operateEdit->setMaxLength(30);
//为文本框设置字体
QFont font = operateEdit->font();
font.setPointSize(font.pointSize() + 8);
operateEdit->setFont(font);
oneButton = new QPushButton;
oneButton->setText(tr("1"));
oneButton->setFixedHeight(50);
oneButton->setFixedWidth(50);
//其他按钮的声明是一样的
//面板
firstLayout = new QHBoxLayout;
firstLayout->addWidget(oneButton);
firstLayout->addWidget(twoButton);
firstLayout->addWidget(threeButton);
firstLayout->addWidget(addButton);
firstLayout->addWidget(sinButton);
firstLayout->addWidget(clearButton);
firstLayout->addWidget(backspaceButton);
//其他面板的添加按钮的过程类似
//主窗口
mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(operateEdit);
mainLayout->addLayout(firstLayout);
mainLayout->addLayout(secondLayout);
mainLayout->addLayout(thirdLayout);
mainLayout->addLayout(fourthLayout);
//信号和槽
connect(zeroButton,SIGNAL(clicked()),this,SLOT(zeroButtonPress()));
connect(oneButton,SIGNAL(clicked()),this,SLOT(oneButtonPress()));
connect(twoButton,SIGNAL(clicked()),this,SLOT(twoButtonPress()));
connect(threeButton,SIGNAL(clicked()),this,SLOT(threeButtonPress()));
connect(fourButton,SIGNAL(clicked()),this,SLOT(fourButtonPress()));
connect(fiveButton,SIGNAL(clicked()),this,SLOT(fiveButtonPress()));
connect(sixButton,SIGNAL(clicked()),this,SLOT(sixButtonPress()));
connect(sevenButton,SIGNAL(clicked()),this,SLOT(sevenButtonPress()));
connect(eightButton,SIGNAL(clicked()),this,SLOT(eightButtonPress()));
connect(nineButton,SIGNAL(clicked()),this,SLOT(nineButtonPress()));
connect(decimalButton,SIGNAL(clicked()),this,SLOT(decimalButtonPress()));
connect(addButton,SIGNAL(clicked()),this,SLOT(addButtonPress()));
connect(subButton,SIGNAL(clicked()),this,SLOT(subButtonPress()));
connect(mulButton,SIGNAL(clicked()),this,SLOT(mulButtonPress()));
connect(divButton,SIGNAL(clicked()),this,SLOT(divButtonPress()));
connect(sinButton,SIGNAL(clicked()),this,SLOT(sinButtonPress()));
connect(cosButton,SIGNAL(clicked()),this,SLOT(cosButtonPress()));
connect(tanButton,SIGNAL(clicked()),this,SLOT(tanButtonPress()));
connect(sqrtButton,SIGNAL(clicked()),this,SLOT(sqrtButtonPress()));
connect(powButton,SIGNAL(clicked()),this,SLOT(powButtonPress()));
connect(rightPerButton,SIGNAL(clicked()),this,SLOT(rightPerButtonPress()));
connect(leftPerButton,SIGNAL(clicked()),this,SLOT(leftPerButtonPress()));
connect(equButton,SIGNAL(clicked()),this,SLOT(equButtonPress()));
connect(clearButton,SIGNAL(clicked()),this,SLOT(clearButtonPress()));
connect(backspaceButton,SIGNAL(clicked()),this,SLOT(backspaceButtonPress()));
connect(binaryButton,SIGNAL(clicked()),this,SLOT(binaryButtonPress()));
connect(octButton,SIGNAL(clicked()),this,SLOT(octButtonPress()));
connect(hexButton,SIGNAL(clicked()),this,SLOT(hexButtonPress()));
input= "0";//初始化运算操作数2为0
}
//然后是析构函数的实现:
calculatorWindow::~calculatorWindow()//析构函数主要完成对构造函数中所声明的QLineEdit、QPushButton、QHBoxLayout、QVBoxLayout类的对象的回收工作(可以不定义析构函数,程序运行结束时会自动调用系统默认的析构函数)
{
if (operateEdit != NULL) //
{
operateEdit = NULL;
delete operateEdit;
}
if (zeroButton != NULL)
{
zeroButton = NULL;
delete zeroButton;
}
}
ButtonPress.cpp
#include "calculatorWindow.h"
//数字键和最基本的运算符建的实现
void calculatorWindow::numButtonPress(char num)
{
if(opreate){
//判断是否开始第二次计算,如果opreate为真,单击数字键就表示开始新的计算
operateEdit->setText(0);
opreate = 0; //将文本置为零,将opreate置为0,一边下一次输入表达式
}
if(input=="0")//如果当前显示框为0
{
input=num;//变0为num
}
else
{
input= operateEdit->text();
input.append(num);
}
operateEdit->setText(input);//更新显示框中的显示信息
opreated = 0;
//输入数字后将opreate改为1,等待运算符输入
}
//一元运算符的响应函数
void calculatorWindow::danButtonPress(char op)
{
if(input=="0")//如果当前显示框为0
{
input=op;//变0为num
}
else
{
input= operateEdit->text();
input.append(op);
}
operateEdit->setText(input);//更新显示框中的显示信息
}
//二元运算符响应事件
void calculatorWindow::opreateButtonPress(char op)
{
//实现不能连续输入运算符
//如果前面的字符为运算符,则opreated = 1,不能再次输入运算符。
//只有opreated = 0时才可以输入运算符
if(!opreated)
{
opreate = 0;//只有opreate为假时才可以输入运算符
if(!opreate){
if(input=="0")//如果当前显示框为0
{
input=op;//变0为num
}
else
{
input= operateEdit->text();
input.append(op);
}
operateEdit->setText(input);//更新显示框中的显示信息
}
opreated = 1;
}
}
//二元运算符按键处理函数
void calculatorWindow::opreateButtonPress(char op)
{
//实现不能连续输入运算符
//如果前面的字符为运算符,则opreated = 1,不能再次输入运算符。
//只有opreated = 0时才可以输入运算符
if(!opreated)
{
opreate = 0;//只有opreate为假时才可以输入运算符
if(!opreate){
if(input=="0")//如果当前显示框为0
{
input=op;//变0为num
}
else
{
input= operateEdit->text();
input.append(op);
}
operateEdit->setText(input);//更新显示框中的显示信息
}
opreated = 1;
}
}
//数字键的实现
void calculatorWindow::oneButtonPress()
{
numButtonPress('1');
}
void calculatorWindow::twoButtonPress()
{
numButtonPress('2');
}
void calculatorWindow::threeButtonPress()
{
numButtonPress('3');
}
void calculatorWindow::fourButtonPress()
{
numButtonPress('4');
}
void calculatorWindow::fiveButtonPress()
{
numButtonPress('5');
}
void calculatorWindow::sixButtonPress()
{
numButtonPress('6');
}
void calculatorWindow::sevenButtonPress()
{
numButtonPress('7');
}
void calculatorWindow::eightButtonPress()
{
numButtonPress('8');
}
void calculatorWindow::nineButtonPress()
{
numButtonPress('9');
}
void calculatorWindow::zeroButtonPress()
{
numButtonPress('0');
}
//运算符的按键响应
void calculatorWindow::addButtonPress()
{
opreateButtonPress('+');
}
void calculatorWindow::subButtonPress()
{
opreateButtonPress('-');
}
void calculatorWindow::mulButtonPress()
{
opreateButtonPress('*');
}
void calculatorWindow::divButtonPress()
{
opreateButtonPress('/');
}
//小数点按键处理
void calculatorWindow::decimalButtonPress()
{
numButtonPress('.');
}
//三角函数的实现,考虑到运算的一致性,便于封装函数,故运算规则只能是先输入数字,后输入运算符
//在这里三角函数只是计算了弧度制的
void calculatorWindow::sinButtonPress()
{
opreateButtonPress('S');
}
void calculatorWindow::cosButtonPress()
{
opreateButtonPress('C');
}
void calculatorWindow::tanButtonPress()
{
opreateButtonPress('T');
}
//开方和平方的运算响应事件
void calculatorWindow::sqrtButtonPress()
{
opreateButtonPress('Q');
}
void calculatorWindow::powButtonPress()
{
opreateButtonPress('W');
}
//括号按键响应事件
void calculatorWindow::rightPerButtonPress()
{
numButtonPress('(');
}
void calculatorWindow::leftPerButtonPress()
{
numButtonPress(')');
}
//二进制的转换
void calculatorWindow::binaryButtonPress()
{
hexChange(2);
opreate = 1;
}
//八进制的转换
void calculatorWindow::octButtonPress()
{
hexChange(8);
opreate = 1;
}
//十六进制的转换,由于牵扯到非数字字符,暂时并未实现
void calculatorWindow::hexButtonPress()
{
if(opreate){//判断是否开始第二次计算,如果opreate为真,单击数字键就表示开始新的计算
operateEdit->setText(0);
opreate = 0; //将文本置为零,将opreate置为0,一边下一次输入表达式
}
QString a = operateEdit->text();
int temp = a.toInt();
string result = decToHex(temp);
operateEdit->setText(QString::fromStdString(result));
opreate = 1;
}
//功能键
//等号按键的实现
void calculatorWindow::equButtonPress()
{
opreateButtonPress('=');
calculate();
opreate = 1;
}
//Clear键的实现
void calculatorWindow::clearButtonPress()
{
input="0";//把运算操作数2清零
operateEdit->setText(input); //更新显示框中的显示内容
}
//退格键的实现
void calculatorWindow::backspaceButtonPress()
{
if(!opreate)
{
input = operateEdit->text();
input.chop(1);
if (input.isEmpty()) {
input = "0";
}
operateEdit->setText(input);
}
}
Calculator.cpp
#include <string>
#include <stdio.h>
#include <iostream>
#include <ctype.h>
#include <stdlib.h>//用atof()时需要用到该头文件
#include <math.h>
#include "calculatorwindow.h"
#include <sstream>
using namespace std;
#define MAX 30//计算器输入的数字最大的字符个数为30
//异常处理函数
void calculatorWindow::abortOperation()
{
input="0";
operateEdit->setText(tr("####"));
}
//表达式计算
void calculatorWindow::calculate()
{
operatorStack.push('#');
QString input = operateEdit->text();
string s = input.toStdString();
//cout<
int i = 0;
int j;
char temp[MAX];
float c;
while(s[i]!='\0')
{
if(isdigit(s[i]))
{
j = 0;
while(isdigit(s[i])||s[i] =='.')
{
try
{
if(j < MAX -1)
{
temp[j] = s[i];
j++;
i++;
}
}
catch(exception e)
{
numStack.clear();
operatorStack.clear();
return ;
//cout<<"输入的数字的位数超出计算器的规定长度!请重新输入算式"<
abortOperation();
}
}
temp[j] = '\0';
c=atof(temp);//类型转换,将字符字符数组转换为数字
try
{
if(!numStack.full())
numStack.push(c);
}
catch(exception e)
{
//cout<<"输入的数字的位数超出计算器的规定长度!请重新输入"<
abortOperation();
}
}//如果s[i]是数字或者是小数点那么就存入数组temp中,直到符号出现,然后将数字压入数字栈
else
{
char stackin = operatorStack.pop('a');//取符号栈的栈顶元素
/*此处加一个对负数的判断,因为只有开头时负数才直接可以写符号*/
//if(i == 0 && s[i] == '-')
//{
//}
while(!operatorCompare(s[i],stackin))//栈顶元素与栈外元素比较,如果栈内符号优先级大于等于栈外符号优先级则执行
{
if(stackin == '#')
{
//cout<<"计算结果:"<
//cout<
operateEdit->setText(QString::number(numStack.pop(1)));
goto loop2;//重启计算器
}
if(s[i] == ')')//这里可以用等于来判断
{
if(stackin == '(')
{
operatorStack.remove('a');
}//如果下一个符号是')'并且栈内符号是'(',那么符号'('出栈。
goto loop1;
}
else
{
partCalculate(stackin);//栈内符号优先级较栈外符号优先级高,局部计算
operatorStack.remove('a');//使用完的符号从符号栈中移除
stackin = operatorStack.pop('a');//再与符号栈中的下一个符号进行比较
}
}//栈内符号比栈外符号优先级高,计算,符号出栈,数字压栈
operatorStack.push(s[i]);
loop1:
i++;//这里是为了去掉两个相邻的()进行下一步计算
}//如果去到的是符号,那么与栈内符号比较
}
loop2:
return;
//calculate();
//cout<
//operateEdit->setText(QString::number(numStack.pop(1)));
}//表达式计算
bool calculatorWindow::operatorCompare(char stackOut,char stackIn)//operatorA为栈内符号,operationB为栈外符号
{
int tempOut ,tempIn;
switch(stackOut)
{
case '+':
case '-':
tempOut = 1;
break;
case '*':
case '/':
tempOut = 3;
break;
case '(':
tempOut = 7;
break;
case ')':
tempOut = 0;
break;
case 'S':
case 'C':
case 'T':
case 'O':
case 'X':
case 'Q':
case 'W':
tempOut = 5;
break;
/***修改处*******/
case '=':
tempOut = -1;
case '#':
tempOut = -2;
break;
/***修改处*******/
default:
abortOperation();//这里要对异常进行处理,如何处理后面考虑
break;
}
switch(stackIn)
{
case '+':
case '-':
tempIn = 2;
break;
case '*':
case '/':
tempIn = 4;
break;
case '(':
tempIn = 0;
break;
case ')':
tempIn = 7;
break;
case 'S':
case 'C':
case 'T':
case 'X':
case 'Q':
case 'W':
tempIn = 5;
break;
case '#':
tempIn = -1;
break;
default:
abortOperation();//这里要对异常进行处理,如何处理后面考虑
break;//这里可以尝试用goto语句,或者是用重新调用一个函数
}
if(tempOut > tempIn)
{
return true;
}
else
{
return false;
}
}//该函数实现的是对栈外符号和栈内符号的比较
void calculatorWindow::partCalculate(char oper)
{
float temp1;
float temp2;
switch(oper)
{
case 'S':
temp1 = numStack.remove(1);
temp1 = sin(temp1);
numStack.push(temp1);
break;
case 'C':
temp1 = numStack.remove(1);
temp1 = cos(temp1);
numStack.push(temp1);
break;
case 'T':
temp1 = numStack.remove(1);
temp1 = tan(temp1);
numStack.push(temp1);
break;
case 'X':
temp1 = numStack.remove(1);
if(temp1 == 0)
{
abortOperation();
}
else
{
temp1 = 1/temp1;
numStack.push(temp1);
}
break;
case 'Q':
temp1 = numStack.remove(1);
temp1 = sqrt(temp1);
numStack.push(temp1);
break;
case 'W':
temp1 = numStack.remove(1);
temp1 = pow(temp1,2);
numStack.push(temp1);
break;
case '+':
temp1 = numStack.remove(1);
temp2 = numStack.remove(1);
temp1 = temp1 + temp2;
numStack.push(temp1);
break;
case '-':
temp1 = numStack.remove(1);
temp2 = numStack.remove(1);
temp1 = temp2 - temp1;
numStack.push(temp1);
break;
case '*':
temp1 = numStack.remove(1);
temp2 = numStack.remove(1);
temp1 = temp1 * temp2;
numStack.push(temp1);
break;
case '/':
temp1 = numStack.remove(1);
temp2 = numStack.remove(1);
temp1 = temp2 / temp1;
numStack.push(temp1);
break;
}
}//栈内符号比栈外符号优先级高,取数字栈中的一个或两个操作数进行计算。
//实现十进制到二进制和十六进制的转换
long int calculatorWindow::changeHexadecimal(int num,int power)
{
int b,i,t;
long int sum=0,s;
for(i=0; num>=power; i++)
{
b=num%power;
num=num/power;
s=1;
for(t=0; t
s=s*10;
sum=sum+b*s;
}
s=num;
for(t=1; t<=i; t++) s=s*10;
sum=sum+s;
return sum;
}
//进制转换函数
void calculatorWindow::hexChange(int num)
{
if(opreate){//判断是否开始第二次计算,如果opreate为真,单击数字键就表示开始新的计算
operateEdit->setText(0);
opreate = 0; //将文本置为零,将opreate置为0,一边下一次输入表达式
}
QString a = operateEdit->text();
int temp = a.toInt();
long int result = changeHexadecimal(temp,num);
operateEdit->setText(QString::number(result));
}
//十进制转换成十六进制的函数
//将十六进制中大于等于十的数转换为ABCDEF
string calculatorWindow::changeToABC(int num)
{
char c ;
string s;
string str;
stringstream stream;
//stream << c;
str = stream.str();
switch(num)
{
case 10:
c = 'A';
stream << c;
s = stream.str();
break;
case 11:
c = 'B';
stream << c;
s = stream.str();
break;
case 12:
c = 'C';
stream << c;
s = stream.str();
break;
case 13:
c = 'D';
stream << c;
s = stream.str();
break;
case 14:
c = 'E';
stream << c;
s = stream.str();
break;
case 15:
c = 'F';
stream << c;
s = stream.str();
break;
}
return s;
}
string calculatorWindow::decToHex(int number)
{
string s ="" ;
ostringstream tempC;
string tempS;
int tempN;
for(; number > 16; )
{
tempN = number%16;
number=number/16;
if(tempN >= 10)
{
//cout<< s <
s= s + changeToABC(tempN);
}
else
{
tempC<
cout<
}
}
if(number < 16)
{
if(number >= 10)
{
//cout<< s <
s= s + changeToABC(number);
}
else
{
tempC<
//cout<
s = s + tempC.str();
}
}
//翻转字符串
int len = s.length();
string sswap = "";
for(int i = len - 1;i >= 0;i--)
{
sswap = sswap + s[i];
}
return sswap;
}
Stack.cpp和mian.cpp在这里就不具体介绍了,详细见代码文件!