widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QStack>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
QString expression; //接受通过按钮输入的表达式
public:
Widget(QWidget *parent = nullptr);
~Widget();
char compare(char a,char b); //用于判断运算符栈栈顶运算符 a1 与读入运算符 a2 之间的优先关系函数
double Operate(double m,double n,char x);//用于计算两个操作数和一个操作符
double jointnum(QString str,int &i); //用于将一个操作数转换为double类型数,以便于存入操作数栈
void caculator() ;
private slots:
void on_num_0_clicked();
void on_num_1_clicked();
void on_num_2_clicked();
void on_num_3_clicked();
void on_num_4_clicked();
void on_num_5_clicked();
void on_num_6_clicked();
void on_num_7_clicked();
void on_num_8_clicked();
void on_num_9_clicked();
void on_sign_jia_clicked();
void on_sign_jian_clicked();
void on_sign_cheng_clicked();
void on_sign_chu_clicked();
void on_sign_dengyu_clicked();
void on_sign_zuokuo_clicked();
void on_sign_youkuo_clicked();
void on_sign_delete_clicked();
void on_sign_clear_clicked();
void on_sign_dian_clicked();
private:
Ui::Widget *ui;
QStack <double> opnd; // Operand stack操作数栈
QStack <char> optr; // Operator stack运算符栈
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "./ui_widget.h"
#include <QStack>
#include <QWidget>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("计算器");
}
Widget::~Widget()
{
delete ui;
}
//信号与槽 当点击计算器上各个按钮时产生操作,将输入的表达式存入QString类型的变量expression中
/* 关联 connect(ui->pushbutton-2,signal(clicked),this,slot(myslot()))
* 自定义 connect(this,signal(mysignal),this,)不用实现
* 直接转到槽
* */
int cout=0;
int flag=1;
void Widget::on_num_0_clicked()
{
expression +="0";
ui->input_0->setText(expression);
cout++;
if(cout>=2){
if(expression[cout-2]=='/') ui->input->setText("表达式错误"); //除数为0的情况
}
}
void Widget::on_num_1_clicked()
{
expression +="1";
ui->input_0->setText(expression);
cout++;
}
void Widget::on_num_2_clicked()
{
expression +="2";
ui->input_0->setText(expression);
cout++;
}
void Widget::on_num_3_clicked()
{
expression +="3";
ui->input_0->setText(expression);
cout++;
}
void Widget::on_num_4_clicked()
{
expression +="4";
ui->input_0->setText(expression);
cout++;
}
void Widget::on_num_5_clicked()
{
expression +="5";
ui->input_0->setText(expression);
cout++;
}
void Widget::on_num_6_clicked()
{
expression +="6";
ui->input_0->setText(expression);
cout++;
}
void Widget::on_num_7_clicked()
{
expression +="7";
ui->input_0->setText(expression);
cout++;
}
void Widget::on_num_8_clicked()
{
expression +="8";
ui->input_0->setText(expression);
cout++;
}
void Widget::on_num_9_clicked()
{
expression +="9";
ui->input_0->setText(expression);
cout++;
}
void Widget::on_sign_jia_clicked()
{
cout++;
flag=1;
expression +="+";
ui->input_0->setText(expression);
if(cout>=2) {if(expression[cout-2]=='-'||expression[cout-2]=='*'||expression[cout-2]=='/'
||expression[cout-2]=='(')
ui->input->setText("表达式错误");
else {if (expression[cout-2]=='+'){
expression.remove(expression.length()-1,1);
cout--;
}
}
}
else {
ui->input->setText("表达式错误");
}
}
void Widget::on_sign_jian_clicked()
{
expression +="-";
flag=1;
ui->input_0->setText(expression);
cout++;
if(cout>=2) {if(expression[cout-2]=='+'||expression[cout-2]=='*'||expression[cout-2]=='/'
||expression[cout-2]=='(')
ui->input->setText("表达式错误");
else {if (expression[cout-2]=='-'){
expression.remove(expression.length()-1,1);
cout--;}
}
}
}
void Widget::on_sign_cheng_clicked()
{
expression +="*";
ui->input_0->setText(expression);
cout++;
flag=1;
if(cout>=2) {if(expression[cout-2]=='-'||expression[cout-2]=='+'||expression[cout-2]=='/'
||expression[cout-2]=='(')
ui->input->setText("表达式错误");
else {if (expression[cout-2]=='*'){
expression.remove(expression.length()-1,1);
cout--;}
}
}
else {
ui->input->setText("表达式错误");
}
}
void Widget::on_sign_chu_clicked()
{
expression +="/";
flag=1;
ui->input_0->setText(expression);
cout++;
if(cout>=2) {if(expression[cout-2]=='-'||expression[cout-2]=='*'||expression[cout-2]=='+'
||expression[cout-2]=='(')
ui->input->setText("表达式错误");
else {if (expression[cout-2]=='/'){
expression.remove(expression.length()-1,1);
cout--;}
}
}
else {
ui->input->setText("表达式错误");
}
}
void Widget::on_sign_zuokuo_clicked()
{
expression +="(";
ui->input_0->setText(expression);
cout++;
if(cout>=2) { if (expression[cout-2]=='(')
{
expression.remove(expression.length()-1,1);
cout--;
}
else {
if(expression[cout-2]<='9'&&expression[cout-2]>='0')
{ui->input->setText("表达式错误");}
}
}
}
void Widget::on_sign_youkuo_clicked()
{
expression +=")";
ui->input_0->setText(expression);
cout++;
int i=cout; //处理缺少左括号
while(i>0){
if(expression[i-1]=='(') {
break;
}
else {
i--;
}
}
if (i==0) {
if(expression[0]!='(')
ui->input->setText("表达式错误");
}
//处理同加减乘除
if(cout>=2) {if(expression[cout-2]=='-'||expression[cout-2]=='*'||expression[cout-2]=='+'
||expression[cout-2]=='('||expression[cout-2]=='/')
{ui->input->setText("表达式错误");
//qDebug()<<"cuowu";
}
else {if (expression[cout-2]==')'){
expression.remove(expression.length()-1,1);
cout--;}
}
}
else {
ui->input->setText("表达式错误");
}
}
void Widget::on_sign_dian_clicked()
{
if(flag==0) ui->input->setText("表达式错误");
expression +=".";
cout++;
flag=0;
if(cout<2){
expression[0]='0';
expression +="."; //处理输入的第一个运算符为小数点的情况
cout++;
}
else{
if(expression[cout-1]==expression[cout-2])
{
expression.remove(expression.length()-1,1);
cout--;}
}
ui->input_0->setText(expression);
}
void Widget::on_sign_delete_clicked()
{
expression.remove(expression.length()-1,1);
ui->input_0->setText(expression);
cout--;
}
void Widget::on_sign_clear_clicked()
{
ui->input_0->clear();
ui->input->clear();
expression.clear();
cout=0;
}
//compare 用于判断运算符栈栈顶运算符op1与读入运算符op2之间的优先关系函数
char Widget::compare(char op1,char op2){
int i,j;//i表示op1,j表示op2
switch(op1){
case'+':i=0;break;
case'-':i=1;break;
case'*':i=2;break;
case'/':i=3;break;
case'(':i=4;break;
case')':i=5;break;
case'#':i=6;break; // # 是表达式的结束符
}
switch(op2){
case'+':j=0;break;
case'-':j=1;break;
case'*':j=2;break;
case'/':j=3;break;
case'(':j=4;break;
case')':j=5;break;
case'#':j=6;break;
}
const int maxn=110;
char priority[7][7]={
{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},
{'>','>','>','>','<','>','>'},
{'<','<','<','<','<','=','0'}, // 此行"("=")"表示左右括号相遇,括号内运算已完成
{'>','>','>','>','0','>','>'},
{'<','<','<','<','<','0','='} // "=" 表示整个表达式求值完毕
}; // "0"表示不可能出现这种情况
return priority[i][j];
}
//用于计算两个操作数和一个运算符
double Widget::Operate(double m,double n,char x){
if(x=='+')
return m+n;
if(x=='-')
return n-m;
if(x=='*')
return m*n;
if(x=='/'){
if(m == 0)
{
ui->input->setText("语法错误"); //校验
return 0;
}
return n/m;
}
}
//处理操作数,将字符串转变为double返回一个数,每次只处理一个数
double Widget::jointnum(QString str,int &i){
QString temp;
double result;
//处理小数点前面的部分
while(str[i]>='0'&&str[i]<='9'){
temp+=str[i];
i++;
}
//遇到小数点
if(str[i]=='.'){
temp+=str[i];
i++;
while(str[i]>='0'&&str[i]<='9'){
temp+=str[i];
i++;
}
}
result=temp.toDouble();
return result;
}
void Widget::on_sign_dengyu_clicked(){
int i=cout,j=cout; //处理缺少右括号
while(i>0){
if(expression[i-1]=='(') {
while(j>0){
if(expression[j-1]==')')break;
else j--;
}
break;
}
else {
i--;
}
}
if(i!=0&&j==0) ui->input->setText("表达式错误");
else {
cout++;
if(cout==1) ui->input->setText("请输入表达式");
else {if(cout>=2) {if(expression[cout-2]=='-'||expression[cout-2]=='*'||expression[cout-2]=='+'||expression[cout-2]=='(')
ui->input->setText("表达式错误");
else caculator();
}
}
}
}
//双栈法求表达式
void Widget::caculator()
{
optr.clear();
opnd.clear();
expression = ui->input_0->text();
QString out=expression;
out+="=";
expression +='#'; //目的是为了结束循环
if(expression[0]=='-'){
expression='0'+expression; //处理第一个数字是负数的情况
}
if(expression.isEmpty()) return;
optr.push('#'); //#至于栈底
int i=0;
double num,a,b; //num临时保存操作数 a、b用于保存参与运算的操作数
char op1,op2,op; //op1栈顶运算符,op2当前的运算符,op用于保存出栈参与运算的运算符
while(!optr.empty()){ //循环条件的设置
if(expression[i]=='0'||expression[i]=='1'||expression[i]=='2'||expression[i]=='3'||
expression[i]=='4'||expression[i]=='5'||expression[i]=='6'||expression[i]=='7'||
expression[i]=='8'||expression[i]=='9'||expression[i]=='.'){
num=jointnum(expression,i);
opnd.push(num); //每if一次入栈一个操作数,直至循环结束
}
//遇到运算符则执行else语句,此时expression[i]指向运算符,因为jointnum函数采用了引用传递
else{
//取运算符栈顶符号进行优先级比较
op1=optr.top();
op2=expression[i].toLatin1();
switch(compare(op1,op2)){
case '<':{
//栈顶小于当运算符 入栈
optr.push(op2);
i++; //指向下一个字符
}break;
case '>':{
//栈顶大于当前运算符 出栈 运算 结果存入操作数栈
op=optr.pop();
a=opnd.pop();
b=opnd.pop();
//qDebug()<<a<<op<<b;
opnd.push(Operate(a,b,op));
}break;
case '=':{
//两种情况1、当前为右括号 2、遇到#,即结束标志
op1=optr.pop();
if(op1!='#') i++;
}break;
case '0':{
//语法错误
ui->input->setText("语法错误");
}break;
}
}
}
num=opnd.pop();//计算结果存储在num里
QString str_num=QString::number(num,'g',10);
ui->input->setText(QString::number(num));
ui->history->append(out+QString::number(num));
}