Qt制作计算器

前言

运用数据队列中的栈知识,使用Qt制作简易的计算器

功能概述

①支持中缀表达式的基本四则运算

②支持软(软件自带键盘),硬(实体键盘)键盘均可操作,并且按键时触发小特效

③支持查看历史记录

核心思路

将用户输入的表达式分解为运算符操作数两类

运算符:"+", "-", "*", "/", "(", ")"

操作数: 即0~9和小数点的组合

然后设置两个栈:运算符栈optr和操作数栈opnd

首先置操作数栈opnd为空,再先将一个操作符"="压入运算符栈optr中作为栈底元素,然后从左到右遍历用户输入的表达式,表达式是一个字符串,记作infix,只要没有遍历到运算符,那么这一串数字整体就是一个操作数,将其压入opnd栈中,若遍历到运算符,则按下列规则计算:

①若infix[i]的优先级高于optr栈顶的运算符,则将infix[i]压入optr栈中

②若infix[i]的优先级低于optr栈顶的运算符,则弹出optr栈顶的运算符,并从opnd弹出两个操作数,进行相应算术运算后,结果再压入opnd栈中

③若infix[i]是"(",则压入optr栈中

④若infix[i]是")",并且optr栈顶是“(”,则optr退栈,从而消去了左右括号,根据规则②计算

⑤若infix[i]是"=","="优先级最低,则optr退栈,用弹出的运算符与从opnd栈中弹出的两个操作数进行运算,结果压入opnd栈中,这个过程一致持续到optr栈只剩下"="为止,运算结束

                                                          运算符之间的优先级关系

运算符 = *和/ +和-
栈内优先级 0 1 5 3 6
栈外优先级 0 6 4 2 1

功能演示

源代码

#include <QWidget>
#include<QStack>
#include<QDebug>
#include<QKeyEvent>
#include<QPushButton>
#include<QThread>
#include<QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    double jointNum(QString str,int &i);//提取操作数
    int in_priority(char ch);//栈内运算符优先级
    int out_priority(char ch);//栈外运算符优先级
    int compare_priority(int in,int out); //比较栈内外的优先级
    int calcualate_num(double num1,double num2,char oper);//根据运算符计算两个操作数
    void keyPressEvent(QKeyEvent *event);
    void keyReleaseEvent(QKeyEvent *event);
    void btn_highlight(QPushButton* btn); //键盘按下高亮
    void btn_release(QPushButton* btn);//键盘释放
    void de_weight(QVector<QString> &vec);//去重

private slots:
    void on_btn_equal_clicked();

    void on_btn_clear_clicked();

    void on_btn_back_clicked();

    void on_btn_1_clicked();

    void on_btn_0_clicked();

    void on_btn_point_clicked();

    void on_btn_add_clicked();

    void on_btn_sub_clicked();

    void on_btn_3_clicked();

    void on_btn_2_clicked();

    void on_btn_multiply_clicked();

    void on_btn_6_clicked();

    void on_btn_5_clicked();

    void on_btn_4_clicked();

    void on_btn_divide_clicked();

    void on_btn_9_clicked();

    void on_btn_8_clicked();

    void on_btn_7_clicked();

    void on_btn_right_clicked();

    void on_btn_left_clicked();

private:
    Ui::Widget *ui;
    QStack<char> optr;//运算符栈
    QStack<double> opnd;//操作数栈
    QString infix;//中缀表达式
    QVector<QString> history_infix;//存储历史记录
};
  #include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("计算器");


}

Widget::~Widget()
{
    delete ui;
}

double Widget::jointNum(QString str, int &i)//分割,提取操作数
{
    QString temp;
     ui->le_show->clear();
    double result;
    //138×16-5
    while(str[i]>='0'&&str[i]<='9') //处理小数点之前的部分
    {
        temp += str[i++];
    }
    if(str[i]=='.')//处理小数点之后的部分
    {
        i++;
        temp+='.';
        while(str[i]>='0'&&str[i]<='9') //处理小数点之前的部分
            temp += str[i++];
    }
    result = temp.toDouble();
    return result;
}

int Widget::in_priority(char ch)
{
    int in;
    switch(ch)
    {
        case '=':in = 0;break;
        case '+':in = 3;break;
        case '-':in = 3;break;
        case '*':in = 5;break;
        case '/':in = 5;break;
        case '(':in = 1;break;
        case ')':in = 6;break;
    }
    return in;
}

int Widget::out_priority(char ch)
{
    int out;
    switch(ch)
    {
        case '=':out = 0;break;
        case '+':out = 2;break;
        case '-':out = 2;break;
        case '*':out = 4;break;
        case '/':out = 4;break;
        case '(':out = 6;break;
        case ')':out = 1;break;
    }
    return out;
}

int Widget::compare_priority(int in, int out)
{
    if(in<out)
        return -1;
    else if(in==out)
        return 0;
    else
        return 1;
}

int Widget::calcualate_num(double num1, double num2, char oper)
{
    switch(oper)
    {
    case '+':return num2+num1;
    case '-':return num2-num1;
    case '*':return num2*num1;
    case '/':
    {
        if(num1 == 0)
        {
            QMessageBox::warning(this,"错误","除数为0!!!");
            return 0;
        }

        return num2/num1;
    }
    }
}

void Widget::keyPressEvent(QKeyEvent *event) //键盘事件
{
    infix = ui->le_show->text();
    switch (event->key()) {
    case 0x30:infix+="0";btn_highlight(ui->btn_0);break;
    case 0x31:infix+="1";btn_highlight(ui->btn_1);break;
    case 0x32:infix+="2";btn_highlight(ui->btn_2);break;
    case 0x33:infix+="3";btn_highlight(ui->btn_3);break;
    case 0x34:infix+="4";btn_highlight(ui->btn_4);break;
    case 0x35:infix+="5";btn_highlight(ui->btn_5);break;
    case 0x36:infix+="6";btn_highlight(ui->btn_6);break;
    case 0x37:infix+="7";btn_highlight(ui->btn_7);break;
    case 0x38:infix+="8";btn_highlight(ui->btn_8);break;
    case 0x39:infix+="9";btn_highlight(ui->btn_9);break;
    case 0x2b:infix+="+";btn_highlight(ui->btn_add);break;
    case 0x2d:infix+="-";btn_highlight(ui->btn_sub);break;
    case 0x2a:infix+="*";btn_highlight(ui->btn_multiply);break;
    case 0x2f:infix+="/";btn_highlight(ui->btn_divide);break;
    case 0x28:infix+="(";btn_highlight(ui->btn_left);break;
    case 0x29:infix+=")"; btn_highlight(ui->btn_right);break;
    case 0x2e:infix+="."; btn_highlight(ui->btn_point);break;
    case 0x01000003:on_btn_back_clicked();btn_highlight(ui->btn_back);break; //退格
    case 0x01000004:on_btn_equal_clicked();btn_highlight(ui->btn_equal);break; //等于
    case 0x01000005:on_btn_equal_clicked();btn_highlight(ui->btn_equal);break; //等于
    }

    ui->le_show->setText(infix);
}

void Widget::keyReleaseEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case 0x30:btn_release(ui->btn_0);break;
    case 0x31:btn_release(ui->btn_1);break;
    case 0x32:btn_release(ui->btn_2);break;
    case 0x33:btn_release(ui->btn_3);break;
    case 0x34:btn_release(ui->btn_4);break;
    case 0x35:btn_release(ui->btn_5);break;
    case 0x36:btn_release(ui->btn_6);break;
    case 0x37:btn_release(ui->btn_7);break;
    case 0x38:btn_release(ui->btn_8);break;
    case 0x39:btn_release(ui->btn_9);break;
    case 0x2b:btn_release(ui->btn_add);break;
    case 0x2d:btn_release(ui->btn_sub);break;
    case 0x2a:btn_release(ui->btn_multiply);break;
    case 0x2f:btn_release(ui->btn_divide);break;
    case 0x28:btn_release(ui->btn_left);break;
    case 0x29: btn_release(ui->btn_right);break;
    case 0x2e: btn_release(ui->btn_point);break;
    case 0x01000003:btn_release(ui->btn_back);break; //退格
    case 0x01000004:btn_release(ui->btn_equal);break; //等于
    case 0x01000005:btn_release(ui->btn_equal);break; //等于
    }
}

void Widget::btn_highlight(QPushButton *btn) //按下效果
{
    btn->setStyleSheet("QPushButton{background-color: rgb(200, 200, 200);}");
}

void Widget::btn_release(QPushButton *btn) //释放效果
{
    btn->setStyleSheet("QPushButton{background-color: rgb(240, 240, 240);}");
}

void Widget::de_weight(QVector<QString> &vec) //去重
{
    for(int i = 0;i<vec.size();i++)
    {
        for(int j = i+1;j<vec.size();j++)
        {
            if(vec.at(j) == vec.at(i))
                vec.removeAt(j);
        }
    }
}


void Widget::on_btn_equal_clicked()// =
{
    ui->text_history->clear();
    optr.clear();
    opnd.clear();
    infix = ui->le_show->text(); //获取表达式
    if(infix[0]=="-")
        infix = "0" + infix;
    if(infix.isEmpty())
        return;
    optr.push('='); //=置于栈底,级别最低
    int i = 0;
    double num,a,b;
    char item,ch;
    while(!optr.empty())
    {
        if(infix[i]=="0"||infix[i]=="1"||infix[i]=="2"||infix[i]=="3"||infix[i]=="4"||infix[i]=="5"||
            infix[i]=="6"||infix[i]=="7"||infix[i]=="8"||infix[i]=="9"||infix[i]==".") //数字字符或者.,则拼接并入栈
        {
            num = jointNum(infix,i);
            opnd.push(num);  //数字入栈
        }
        else //操作符
        { //12+13
             item = optr.top();
            switch(compare_priority(in_priority(item),out_priority(infix[i].toLatin1())))//比较运算符优先级,toLatin1:QChar->char
            {
               case -1:
            {
                optr.push(infix[i].toLatin1());//infix[i]优先级高,入栈
                                i++;  //指向下一个字符
            }
                break;
               case 0:
            {
                item = optr.pop(); //删除括号或者=
                if(item!='=')
                    i++;  //指向下一个字符
            }
                break;
               case 1:
            {
                ch = optr.pop(); //infix[i]级别低,弹出一个运算符并弹出两个操作数进行运算后再压栈
                a = opnd.pop();
                b = opnd.pop();
                opnd.push(calcualate_num(a,b,ch)); //运算后结果入栈
            }
            }

        }
    }
    num = opnd.pop();
    if(!opnd.empty())
     qDebug()<<"error";
    QString temp = infix + "="+ QString::number(num);
    history_infix.push_back(temp);
    de_weight(history_infix);//去重
    for(int i = 0;i<history_infix.size();i++)
    {
        ui->text_history->append(history_infix.at(i));
    }
    ui->le_show->setText(QString::number(num));
    infix = QString::number(num);
}

void Widget::on_btn_clear_clicked() //清空
{
    ui->le_show->clear();
    infix.clear();
}

void Widget::on_btn_back_clicked() //退格
{
    infix.remove(infix.length()-1,1);
    ui->le_show->setText(infix);
}

void Widget::on_btn_1_clicked()
{
    infix += "1";
    ui->le_show->setText(infix);
}

void Widget::on_btn_0_clicked()
{
    infix += "0";
    ui->le_show->setText(infix);
}

void Widget::on_btn_point_clicked()
{
    infix += ".";
    ui->le_show->setText(infix);
}

void Widget::on_btn_add_clicked()
{
    infix += "+";
    ui->le_show->setText(infix);
}

void Widget::on_btn_sub_clicked()
{
    infix += "-";
    ui->le_show->setText(infix);
}

void Widget::on_btn_3_clicked()
{
    infix += "3";
    ui->le_show->setText(infix);
}

void Widget::on_btn_2_clicked()
{
    infix += "2";
    ui->le_show->setText(infix);
}

void Widget::on_btn_multiply_clicked()
{
    infix += "*";
    ui->le_show->setText(infix);
}

void Widget::on_btn_6_clicked()
{
    infix += "6";
    ui->le_show->setText(infix);
}

void Widget::on_btn_5_clicked()
{
    infix += "5";
    ui->le_show->setText(infix);
}

void Widget::on_btn_4_clicked()
{
    infix += "4";
    ui->le_show->setText(infix);
}

void Widget::on_btn_divide_clicked()
{
    infix += "/";
    ui->le_show->setText(infix);
}

void Widget::on_btn_9_clicked()
{
    infix += "9";
    ui->le_show->setText(infix);
}

void Widget::on_btn_8_clicked()
{
    infix += "8";
    ui->le_show->setText(infix);
}

void Widget::on_btn_7_clicked()
{
    infix += "7";
    ui->le_show->setText(infix);
}

void Widget::on_btn_right_clicked()
{
    infix += ")";
    ui->le_show->setText(infix);
}

void Widget::on_btn_left_clicked()
{
    infix += "(";
    ui->le_show->setText(infix);
}

项目源码:https://github.com/17359830697/calcualate

这篇文章对你有帮助的话就点个赞吧~

点赞收藏关注就是对我最大的支持~

猜你喜欢

转载自blog.csdn.net/m0_71741835/article/details/128041373