目录
写在前面
上篇文章写了C++中如何实现简单的计算器,先用C++写看来我的选择是正确的,明白了其中的原理再用Qt实现是水到渠成的事,利用Qt实现计算器可视化的核心思想就是如何把在按钮上输入的表达式在文本框中读取!!
一、设计思路
用Qt实现计算器,首先得在ui界面设计一个计算器,当然也可以代码写,我觉得没必要就直接拖啦,而且槽函数也可以直接转到,非常方便。
那么首先如何将按钮上的数字和符号显示在文本框上并读取呢?用setText函数就OK啦,这里有很多种方法,我用的方法是原来文本有的加上输入的,这样就能源源不断输入了,比如点击0的槽函数:
ui->lineEdit->setText(ui->lineEdit->text() +'0');
在这其中等于号的槽函数最重要,因为点击等于号‘=’需要将表达式读取并且计算显示在文本框上,需要注意的是我们在文本框输入的数据编程环境并不能识别,需要将它转换成utf8编码的格式,而输出时又需要转换成字符串的类型:
void calculator::on_pushButtonequal_clicked()
{
string str = ui->lineEdit->text().toStdString();
double result=Stack(str);
//数字转为字符串显示在lineEdit中
ui->lineEdit->setText(QString::number(result));
}
那么到这事情就简单多啦!现在需要编写计算器的表达式计算即可,我这里另外建了一个cpp,方便书写,不懂计算器原理的可以看上篇文章 C++实现简单计算器哦。不够这次肯定是有点不一样的,多了小数点,而且我还加了三角函数的计算,这让calculate的函数参数不得不改变了,上次是两个栈,这次的字符栈我换成了字符型参数。
效果展示:
二、功能实现
- 支持的运算有+,-,*,/,%,^,sqrt
- 支持三角函数运算
- 支持括号运算
- 支持单目运算符+和-的运算
三、设计代码
1.mainwindow.cpp
由于很多都是重复的,这里我只挑不重复的出来。
setFixedSize(360,530);
ui->lineEdit->setReadOnly(true);
//可以设置按钮字体的大小
ui->pushButton0->setFont(QFont("宋体", 15));
//AC槽函数
void calculator::on_pushButtonAC_clicked()
{
ui->lineEdit->clear();
}
//退格槽函数
void calculator::on_pushButtondel_clicked()
{
ui->lineEdit->backspace();
}
2.calculate.cpp
#include"c++calculate.h"
#include<iostream>
#include<string>
#include<stack>
#include<math.h>
using namespace std;
double Stack(string str){//表达式入栈
stack<double> Num;
stack<char> Ch;
int i = 0, j;
int size = str.size();
string num;
char temp;
while (i < size) {
if (str[i] >= '0' && str[i] <= '9') {
j = i;
while ((j < size && str[j] >= '0' && str[j] <= '9') || str[j]=='.') { j++; }
//从下标i开始截取长度为j-i的字符
num = str.substr(i, j - i);
//atof函数将字符串转换成浮点型数
Num.push(atof(num.c_str()));
i = j;
}
else if(str[i]=='('||str[i]==')'){
if (str[i]=='(') Ch.push(str[i]);
else{
while(Ch.top()!='('){
temp=Ch.top();
Ch.pop();
calculate(temp, Num);
}
Ch.pop();//左括号出栈!!这里我忘了两次!!
}
i++;
}
else{
if (Ch.empty()) {
Ch.push(str[i]);
}
else {
while (!Ch.empty()) {
temp = Ch.top();
if (operate(temp) >= operate(str[i])) {
Ch.pop();
calculate(temp, Num);
}
else break;
}
Ch.push(str[i]);
}
i++;
}
}
while(!Ch.empty()){
temp=Ch.top();
Ch.pop();
calculate(temp,Num);
}
return Num.top();
}
int operate(char ch){
if(ch=='(') return 0;
else if(ch=='+'||ch=='-') return 1;
else if(ch=='*'||ch=='/'||ch=='%') return 2;
else if(ch=='s'||ch=='c'||ch=='t'||ch=='q') return 3;
else return 4;
}
void calculate(char temp,stack<double>&Num){
double a=Num.top();Num.pop();
double innum;
if(temp=='!'){
innum=1;
while(a>1){
innum*=a;
a--;
}
}
else if(temp=='s')innum=sin(a);
else if(temp=='c')innum=cos(a);
else if(temp=='t')innum=tan(a);
else if(temp=='q')innum=sqrt(a);
else{
double b=Num.top();Num.pop();
if(temp=='+')innum=b+a;
else if(temp=='-')innum=b-a;
else if(temp=='*')innum=b*a;
else if(temp=='/')innum=b/a;
else if(temp=='^')innum=pow(b,a);
else if(temp=='%')innum=fmodf(b,a);
}
Num.push(innum);
}
注意在添加.cpp文件的时候需要也把.h文件添加,在头文件中添加所需要的类和声明相应的函数。
上述Stack函数和calculate函数都与我之前写的有所不同,因为小数点和三角函数的问题,下面说说他们的不同之处:
1.首先是calculate函数,刚开始我想传入栈作为参数的,但是在三角函数那里,如果出栈两次,程序会运行不了,总之种种原因,最后利用这种先出栈再传入的方式写。
2.小数点需要利用j判断后面有多少位小数,再通过相应的函数转换成浮点型的数。
3.while循环中,之前是等号作为出口,现在明显不行,然后就换了一个出口,其实上篇C++那个这样写也是可以的,方式不同而已。