【Qt项目】制作简单的计算器

使用Qt框架开发的简单的计算器工具,能够实现简单的运算。展示如下:

在这里插入图片描述
核心设计思路:首先将每个点击后的字符存入字符串,此时字符串中存储的即为中缀表达式,然后将该中缀表达式转换为后缀表达式,最后进行计算。
项目代码已上传至码云:https://gitee.com/riabs/calculator

后缀表达式

假设现有表达式:1 * ( 2 + 3 - 4 ) / 5
像这样的表达式称为中缀表达式,生活中平时使用的就是中缀表达式,人很好理解应该先计算哪部分;
而后缀表达式则是计算机更好理解的形式,先说说规则。

=》中缀表达式转后缀表达式的规则:
准备一个字符串和存储操作符的栈。
首先遍历中缀表达式,遇到操作数则直接存入字符串,遇到操作符则进行如下判断:假如栈空或该操作符的优先级高于栈顶操作符,则入栈;否则先弹出栈顶元素并存入字符串,直到栈空或者该操作符的优先级高于栈顶操作符时,将该操作符入栈。遍历完中缀表达式后,依次弹出栈顶元素并存入字符串。
其中比较特殊的是左括号和右括号。当遍历中缀表达式遇到左括号时,不做比较直接入栈,并且其在栈中的优先级最低;当遇见右括号时,弹出栈顶元素并存入字符串,直到栈顶元素为左括号为止,此时弹出左括号,不存入字符串。

/ 注:笔者在编写程序时,遇到操作符后,只要栈空或该操作符的优先级不低于栈顶操作符即可入栈。虽然规则有些许不同,但最终计算结果与如上规则无异,只是计算顺序有所不同。/

=》计算后缀表达式的方式:
准备一个存储操作数的栈。
遍历后缀表达式,遇到操作数则直接入栈;遇到操作符op时弹出栈顶元素a,继续弹出栈顶元素b,以b op a的顺序进行计算,并将结果压入栈中,直到遍历完后缀表达式,输出栈顶元素,即为最终计算结果。

下面以1 * ( 2 + 3 - 4 ) / 5为例,对以上两部分附上过程展示:

1.中缀表达式转后缀表达式
在这里插入图片描述
2.计算后缀表达式
在这里插入图片描述

下面是项目主要实现:

一、创建项目

开发工具:Qt Creator;
使用版本:Qt 5.15.2 MinGW 64-bit;

打开Qt Creator,创建项目,选择 Qt Widgets Application;
在这里插入图片描述
设置名称和路径;
在这里插入图片描述
选择qmake;
在这里插入图片描述
设置类名;
在这里插入图片描述
在构建套件中选择MinGW;
在这里插入图片描述
然后下一步,完成。

二、设计界面

双击calculator.ui,拖入若干Push Button控件,和一个Label控件,并给每个控件设置名称;
在这里插入图片描述
界面完成。

三、主要代码

为了界面看起来更加美观,初始化按键字体和颜色;

//初始化按键字体和颜色
void Calculator::initButtonStyle()
{
    ui->btn_0->setStyleSheet("font-size:20pt");
    ui->btn_1->setStyleSheet("font-size:20pt");
    ui->btn_2->setStyleSheet("font-size:20pt");
    ui->btn_3->setStyleSheet("font-size:20pt");
    ui->btn_4->setStyleSheet("font-size:20pt");
    ui->btn_5->setStyleSheet("font-size:20pt");
    ui->btn_6->setStyleSheet("font-size:20pt");
    ui->btn_7->setStyleSheet("font-size:20pt");
    ui->btn_8->setStyleSheet("font-size:20pt");
    ui->btn_9->setStyleSheet("font-size:20pt");
    ui->btn_point->setStyleSheet("font-size:20pt");
    ui->btn_mod->setStyleSheet("font-size:20pt");
    ui->btn_clear->setStyleSheet("font-size:20pt");
    ui->btn_del->setStyleSheet("font-size:20pt");
    ui->btn_leftBrackets->setStyleSheet("font-size:20pt");
    ui->btn_rightBrackets->setStyleSheet("font-size:20pt");
    ui->btn_add->setStyleSheet("font-size:20pt;background-color:#22aabb");
    ui->btn_sub->setStyleSheet("font-size:20pt;background-color:#bbaaee");
    ui->btn_multi->setStyleSheet("font-size:20pt;background-color:#ffaa22");
    ui->btn_div->setStyleSheet("font-size:20pt;background-color:#ffaaee");
    ui->btn_result->setStyleSheet("font-size:20pt;background-color:RED");
    //显示框颜色和字体
    ui->label->setStyleSheet("font-size:20pt;background-color:WHITE");
}

声明QString类型的成员变量m_expression;利用Qt信号槽机制,点击算数表达式的按钮时,将其对应的字符存入字符串;

//将按键存入表达式
void Calculator::setExperssion()
{
    connect(ui->btn_0,&QPushButton::clicked,this,[=](){
        m_expression += '0';
        emit showLabel();
    });
    connect(ui->btn_1,&QPushButton::clicked,this,[=](){
        m_expression += '1';
        emit showLabel();
    });
    connect(ui->btn_2,&QPushButton::clicked,this,[=](){
        m_expression += '2';
        emit showLabel();
    });
    connect(ui->btn_3,&QPushButton::clicked,this,[=](){
        m_expression += '3';
        emit showLabel();
    });
    connect(ui->btn_4,&QPushButton::clicked,this,[=](){
        m_expression += '4';
        emit showLabel();
    });
    connect(ui->btn_5,&QPushButton::clicked,this,[=](){
        m_expression += '5';
        emit showLabel();
    });
    connect(ui->btn_6,&QPushButton::clicked,this,[=](){
        m_expression += '6';
        emit showLabel();
    });
    connect(ui->btn_7,&QPushButton::clicked,this,[=](){
        m_expression += '7';
        emit showLabel();
    });
    connect(ui->btn_8,&QPushButton::clicked,this,[=](){
        m_expression += '8';
        emit showLabel();
    });
    connect(ui->btn_9,&QPushButton::clicked,this,[=](){
        m_expression += '9';
        emit showLabel();
    });
    connect(ui->btn_point,&QPushButton::clicked,this,[=](){
        m_expression += '.';
        emit showLabel();
    });
    connect(ui->btn_add,&QPushButton::clicked,this,[=](){
        m_expression += '+';
        emit showLabel();
    });
    connect(ui->btn_sub,&QPushButton::clicked,this,[=](){
        m_expression += '-';
        emit showLabel();
    });
    connect(ui->btn_mod,&QPushButton::clicked,this,[=](){
        m_expression += '%';
        emit showLabel();
    });
    connect(ui->btn_multi,&QPushButton::clicked,this,[=](){
        m_expression += '*';
        emit showLabel();
    });
    connect(ui->btn_div,&QPushButton::clicked,this,[=](){
        m_expression += '/';
        emit showLabel();
    });
    connect(ui->btn_leftBrackets,&QPushButton::clicked,this,[=](){
        m_expression += '(';
        emit showLabel();
    });
    connect(ui->btn_rightBrackets,&QPushButton::clicked,this,[=](){
        m_expression += ')';
        emit showLabel();
    });
}

获取到表达式后,将其转换为后缀表达式,方便求值;
在转换为后缀表达式式时,数字或操作符之间用空格隔开;

//转换为后缀表达式
QString Calculator::toRPN(QString str)
{
    QString rpn;
    QStack<QChar> opStack;//存操作符

    for(auto i : str){
        //数字或小数点直接存入字符串
        if((i <= '9' && i >= '0') || i == '.'){
            rpn += i;
        }
        //左括号直接入栈
        if(i == '('){
            opStack.push(i);
        }
        //遇到右括号,出栈栈顶元素直到栈顶元素为左括号
        if(i == ')'){
            while(opStack.top() != '('){
                rpn += ' ';
                rpn += opStack.pop();
            }
            opStack.pop();//将左括号出栈
        }
        //运算符优先级不低于栈顶元素则入栈,否则出栈栈顶元素后入栈
        if(i == '+'||i == '-'){
            rpn += ' ';
                while(!opStack.empty() && opStack.top() != '(' && opStack.top() != '+' && opStack.top() != '-'){
                    rpn += opStack.pop();
                    rpn += ' ';
                }
                opStack.push(i);
            }
        if(i == '*'||i == '/'||i == '%'){
                rpn += ' ';
                opStack.push(i);
            }
    }
    //出栈所有元素
    while(!opStack.empty()){
        rpn += ' ';
        rpn += opStack.pop();
    }
    qDebug() << str << rpn;
    return rpn;
}

然后对后缀表达式进行运算;

double Calculator::operation(QString rpn)
{
    QStack<double> result;
    QString num;
    //遍历后缀表达式
    for(auto i : rpn){
        if((i >= '0' && i <= '9') || i == '.' || i == ' '){
            if((i >= '0' && i <= '9') || i == '.' ){
                num += i;
            }
            if(i == ' '){
                if(!num.isEmpty() && num.at(0) >= '0' && num.at(0) <= '9'){
                    result.push(num.toDouble());
                    num.clear();
                }
            }
        }
        //加法
        if(i == '+'){
            double temp1 = result.pop();
            double temp2 = result.pop();
            result.push(temp2+temp1);
        }
        //减法
        if(i == '-'){
            double temp1 = result.pop();
            double temp2 = result.pop();
            result.push(temp2-temp1);
        }
        //乘法
        if(i == '*'){
            double temp1 = result.pop();
            double temp2 = result.pop();
            result.push(temp2*temp1);
        }
        //除法
        if(i == '/'){
            double temp1 = result.pop();
            double temp2 = result.pop();
            result.push(temp2/temp1);
        }
        //模运算
        if(i == '%'){
            double temp1 = result.pop();
            double temp2 = result.pop();
            result.push(fmod(temp2,temp1));
        }
    }
    return result.top();
}

当点击等于号时,调用求值函数并显示在Label框中。除了等于号,还要处理删除键和清空键的事件;

//特殊按键功能实现
void Calculator::buttonFunction()
{
    //删除键
    connect(ui->btn_del,&QPushButton::clicked,this,[=](){
        if(!m_expression.isEmpty()){
            m_expression.chop(1);//删除字符串最后一位元素
        }
        emit showLabel();
    });

    //清空键
    connect(ui->btn_clear,&QPushButton::clicked,this,[=](){
        m_expression.clear();
        emit showLabel();
    });

    //等于键
    connect(ui->btn_result,&QPushButton::clicked,this,[=](){
        ui->label->setNum(Calculator::operation(toRPN(m_expression)));
    });
}
  • 19
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

库巴巴星人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值