欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于QT5的计算器简单实现

程序员文章站 2024-01-14 11:27:04
...

本人实验室培训作业

需求:实现必要的计算器功能,合理化布局

UI布局:

基于QT5的计算器简单实现

逻辑思维:由于组件中的text()值多为QSTring类型,

1.将槽的操作都写成,往一个大字符串追加信息

2.将字符串解析,利用栈实现数据的先后弹出,操作符的优先顺序

具体实现代码如下:

由于代码中注释足够详细,不再做文字说明:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    QString numInfo;
    void caculate();
    int is_First(char a, char b);
    struct node{
        int flag;
        union{
            double a;
            char  op;
    }num;

//public slots:
//空写slots,编译时会出错,导致无法编译,
//下次务必不要踩雷

};


private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp

//9月29号9:12
//10月3号0:13
//完成基本功能,运算逻辑均正确
//至于科学计算器其它复杂的功能,可日后添加

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QPixmap"
#include "QPushButton"
#include "QIcon"
#include "QPixmap"
#include "QSize"
#include "QDebug"
#include "QFont"
#include "QVector"
#include "QStack"
#include "math.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //设置固定尺寸
    this->setFixedSize(1061,800);
    this->setWindowIcon(QPixmap(":/res/caculater_icon.jpg"));
    this->setWindowTitle("爷的科学计算器");
    //计算符号图标
    //Qicon会自动缩小,这里用Qpixmap先放大
    ui->ride_btn->setIconSize(QSize(100,100));
    ui->ride_btn->setIcon(QIcon(QPixmap(":/res/ride.png")));

    ui->plus_btn->setIconSize(QSize(100,100));
    ui->plus_btn->setIcon(QIcon(QPixmap(":/res/plus.png")));

    ui->reduce_btn->setIconSize(QSize(100,100));
    ui->reduce_btn->setIcon(QIcon(QPixmap(":/res/reduce.png")));

    ui->equal_btn->setIconSize(QSize(100,100));
    ui->equal_btn->setIcon(QIcon(QPixmap(":/res/equal.png")));

    ui->clear_btn->setIconSize(QSize(100,100));
    ui->clear_btn->setIcon(QIcon(QPixmap(":/res/clear.png")));

    ui->back_btn->setIconSize(QSize(100,100));
    ui->back_btn->setIcon(QIcon(QPixmap(":/res/back.png")));

    ui->division_btn->setIconSize(QSize(100,100));
    ui->division_btn->setIcon(QIcon(QPixmap(":/res/division.png")));

    ui->left_btn->setIconSize(QSize(100,100));
    ui->left_btn->setIcon(QIcon(QPixmap(":/res/left.png")));

    ui->right_btn->setIconSize(QSize(100,100));
    ui->right_btn->setIcon(QIcon(QPixmap(":/res/right.png")));

    ui->mod_btn->setIconSize(QSize(100,100));
    ui->mod_btn->setIcon(QIcon(QPixmap(":/res/mod.png")));

    if(this->ui->history_label->text() == ""){
        this->ui->history_label->setText("尚无历史记录");
    }

    //上面发现label字体太小
    QFont font;
    font.setPointSize(20);
    ui->screen_label->setFont(font);

    //通过按钮的text获得按钮代表数字
    this->numInfo = "";
    //写好获取text值,追加字符串之后
    //将btn的clicked与this.slots{}连接
    //不写槽了,用lamda表达式直接模式粘贴复制
    //可以提模板,但是已经写完了
    connect(ui->num1_btn,&QPushButton::clicked,[=](){

            this->numInfo += this->ui->num1_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;

    });
    connect(ui->num2_btn,&QPushButton::clicked,[=](){

            this->numInfo += this->ui->num2_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;

    });
    connect(ui->num3_btn,&QPushButton::clicked,[=](){

            this->numInfo += this->ui->num3_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;

    });
    connect(ui->num4_btn,&QPushButton::clicked,[=](){

            this->numInfo += this->ui->num4_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;

    });
    connect(ui->num5_btn,&QPushButton::clicked,[=](){

            this->numInfo += this->ui->num5_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;

    });
    connect(ui->num6_btn,&QPushButton::clicked,[=](){

            this->numInfo += this->ui->num6_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;

    });
    connect(ui->num7_btn,&QPushButton::clicked,[=](){

            this->numInfo += this->ui->num7_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;

    });
    connect(ui->num8_btn,&QPushButton::clicked,[=](){

            this->numInfo += this->ui->num8_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;

    });
    connect(ui->num9_btn,&QPushButton::clicked,[=](){

            this->numInfo += this->ui->num9_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;

    });
    connect(ui->num0_btn,&QPushButton::clicked,[=](){

            this->numInfo += this->ui->num0_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;


    });
    connect(ui->point_btn,&QPushButton::clicked,[=](){
        if(this->numInfo != " "){
            this->numInfo += this->ui->point_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;
        }

    });
    connect(ui->equal_btn ,&QPushButton::clicked,[=](){
        if(this->numInfo != " "){
            this->caculate();
            this->ui->history_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;
        }
    });
    connect(ui->left_btn,&QPushButton::clicked,[=](){
        if(this->numInfo != " "){
            this->numInfo += this->ui->left_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;
        }
    });
    connect(ui->right_btn,&QPushButton::clicked,[=](){
        if(this->numInfo != " "){
            this->numInfo += this->ui->right_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;
        }
    });
    connect(ui->plus_btn,&QPushButton::clicked,[=](){
        if(this->numInfo != " "){
            this->numInfo += this->ui->plus_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;
        }
    });
    connect(ui->ride_btn,&QPushButton::clicked,[=](){
        if(this->numInfo != " "){
            this->numInfo += this->ui->ride_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;
        }
    });
    connect(ui->reduce_btn,&QPushButton::clicked,[=](){
        if(this->numInfo != " "){
            this->numInfo += this->ui->reduce_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;
        }
    });
    connect(ui->division_btn,&QPushButton::clicked,[=](){
        if(this->numInfo != " "){
            this->numInfo += this->ui->division_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;
        }
    });
    connect(ui->clear_btn,&QPushButton::clicked,[=](){
        this->numInfo = "";
        this->ui->screen_label->setText(this->numInfo);
});
    connect(ui->back_btn,&QPushButton::clicked,[=](){
        this->numInfo = this->numInfo.left(this->numInfo.size()-1);
        ui->screen_label->setText(this->numInfo);
});
    connect(ui->mod_btn,&QPushButton::clicked,[=](){
        if(this->numInfo != " "){
            this->numInfo += this->ui->mod_btn->text();
            this->ui->screen_label->setText(this->numInfo);
            qDebug() << this->numInfo <<endl;
        }
    });
}
//字符串算式解析的方法实现
void MainWindow::caculate(){

//    QVector<double> numlist;
    node nodeList[20];
    double num = 0;
    //设置位置
    int position = 0;
    //设置浮点数标志
    int float_flog = 0;
    //浮点数的小数数量,整数数量
    int num_of_float = 0;
    int num_of_int = 0;
    //获取字符串长度
    int len = this->numInfo.size();
    //老子不用vector了
//    double numlist[len];
    //提取整数
    while(position < len){
        if(numInfo[position] >= '0' && numInfo[position] <= '9'){
            if(!float_flog){
                //将字符串的元素转化为ASCII码
                /*返回相当于QChar的拉丁语-1字符,或0。这主要用于非国际化软件。
                注意:不可能区分非拉丁1字符和拉丁10(NUL)字符。更喜欢使用unicode(),它没有这种模糊性。
                百度结果*/
                num = num*10 + (numInfo[position].toLatin1()-'0');
                ++position;
            }
            else{
                //这一块是算小数部分
                double p = 1;
                for(int k = 0; k < num_of_float;k++){
                    p *= 0.1;
                }
                num += (numInfo[position].toLatin1()-'0')*p;
                num_of_float++;
                ++position;
            }
        }
        //这块是读到小数点,设置标志,设置小数数量(含小数点)
        else if (numInfo[position] == '.') {
            float_flog = 1;
            num_of_float = 1;
            ++position;
        }
        //下面是读到运算符的情况
        else {
                if(num){
                    nodeList[num_of_int].flag = 0;
                    nodeList[num_of_int].num.a = num;
                    qDebug() <<nodeList[num_of_int].num.a;
                    num = 0;
                    ++num_of_int;
                    float_flog = 0;
                    num_of_float = 0;
                    //莫名其妙的bug
//                    qDebug() << QString("%1").arg((numlist.at(1)+numlist.at(2)));
//                    this->numInfo += QString("%1").arg((numlist.at(1)+numlist.at(2)));

//                    while(i>=1){
//                        qDebug() << QString("%1").arg((numlist[i]+numlist[i-1]));
//                        break;
//                    }

            }
                nodeList[num_of_int].flag = 1;
                nodeList[num_of_int].num.op = numInfo[position].toLatin1();
                ++num_of_int;
                ++position;
        }
    }
    //最后一个操作数
    if(num){
        nodeList[num_of_int].flag = 0;
        nodeList[num_of_int].num.a = num;
        qDebug() <<nodeList[num_of_int].num.a;
        ++num_of_int;
        num = 0;
    }
    //利用栈的存储特性,将符号存入并按后缀的顺序读出
    //创建一个Qstack类型的,保存操作符的栈
    QStack<node> signList;
    //临时性出栈操作符
    node temporarySign_node[20];
    int j = 0;
    for(int m = 0; m < num_of_int;){
        if(nodeList[m].flag){

            if(signList.isEmpty()){

                signList.push(nodeList[m++]);
            }
            else{
                node temp = signList.top();
                //判断运算符优先级
                int res = is_First(temp.num.op,nodeList[m].num.op);
                switch (res) {
                case -1:
                    signList.push(nodeList[m++]);
                    break;
                case 1:
                    temporarySign_node[j++] = signList.top();
                    signList.pop();
                    break;
                default:
                    signList.pop();
                    m++;
                    break;
                }

            }
        }
        else {
            temporarySign_node[j++] = nodeList[m++];
        }

    }
    //处理算式中的括号
while(!signList.isEmpty()){
        node tem = signList.top();
        if(tem.num.op != '(' &&tem.num.op != ')'){
            temporarySign_node[j++] = tem;
        }
        signList.pop();
}

QStack<double> last_signList;
double d1 = 0,d2 = 0;
for(int n = 0; n < j ; n++){
    //遇到符号弹出数字,弹出前两个数字
    if(temporarySign_node[n].flag){

        d2 = last_signList.top();
        last_signList.pop();
        d1 = last_signList.top();
        last_signList.pop();

        switch(temporarySign_node[n].num.op)
                {
                    case '+':
                            d1 += d2;
                            break;
                    case '-':
                            d1 -= d2;
                            break;
                    case '*':
                            d1 *= d2;
                            break;
                    case '/':
                            d1 /= d2;
                            break;
                    case '%':
            //注意,这块是浮点数去模,一定要注意用fmod方法,头文件为math.h
            //切记不要再次踩雷
                            d1 = fmod(d1,d2);
                            break;
                     default:
                             break;
                }
                last_signList.push(d1);
    }
    else
        {
            last_signList.push(temporarySign_node[n].num.a);
        }

}
    qDebug() << d1;
    this->numInfo += '=';
    this->numInfo += QString::number(d1);
    this->ui->screen_label->setText(this->numInfo);
}

//返回整形标志的运算符优先级比对结果
int MainWindow::is_First(char a, char b){
    char aim[7][8] = {{ ">><<<>>" },{ ">><<<>>" },{ ">>>><>>" },{ ">>>><>>" },{ "<<<<<=1" },{ ">>>>1>>" },{ "<<<<<1=" }};
        char sta[7] = { '+','-','*','/','(',')','#' };
        char result;
        int i,pa,pb;
        for (i = 0; i<6; i++)
              {
                 if (a == sta[i])
                 {
                     pa = i;
                 }
                 if (b == sta[i])
                 {
                     pb = i;
                 }
              }
        result = aim[pa][pb];
        if(result == '>')return 1;
        else if(result == '<')return -1;
        else return 0;
}
MainWindow::~MainWindow()
{
    delete ui;
}

不可描述的雷:

第一遍运行时,系统会一直报构建方法出错,还不告诉你第几行出错,经查询,把build_debug的文件夹删了就可通顺运行,原因是第一遍程序已经qmake,后面在debug后,再次qmake,build_debug文件夹中的debug文件会与程序重现qmake的步骤相冲突

运行结果图:

基于QT5的计算器简单实现

最大的点:

可以用toDoule方法直接解析字符串算式,不用上面那种繁琐的方法,但是!!!

我已经写完了,淦

相关标签: c++ qt5