QT計算器

程序綜合設計實踐 :用QT實現簡易計算器及貸款計算

1,項目概述

該項目目標是設計開發一個支持連續計算的包括括號( ),求餘%四則運算+ - * /的計算器 Calculator 以及貸款計算功能 Mortgage
本程序爲本人初學一週QT所做,才疏學亦淺,程序中絕對有意想不到的蜜汁bug😆(逃)歡迎你們評論區交流丫。
項目下載地址css

avatar avatar

經過單擊按鈕,輸入並完成如4+5.21+65*(8+16)-2 相似的連續計算,並將運算結果顯示在輸出文本框 lineEdit 中,計算的式子移至上方的 label 中。
支持負數,小數運算,而且精度爲小數點後位。支持簡單的錯誤性檢驗。 CE 清空 Del 後退 More 切換至貸款計算。兩個界面,貸款計算界面不作過多贅述。c++

2,設計步驟 (如下只舉例 Calculator 界面)

界面設計部分

界面設計部分如圖由數組

label (顯示計算的式子)
lineedit (顯示結果或者當前輸入的式子)
以及各個按鈕組成。ide

建立按鈕的時候由於數目有點多,因此咱們能夠用數組保存建立的按鈕 指針 ,後面就能夠直接用 索引 對按鈕進行操控。函數

QT支持用 css 渲染元素。如label->setStyleSheet("font-size:12px;color:grey;border-bottom:1px solid #f1f1f1;border-radius:5px;text-align:right;");佈局

//from widget.cpp

    setFixedSize(400,450);  //固定窗口大小
    setWindowIcon(QIcon(":/icon.png")); //設置icon

    QLineEdit* lineedit = new QLineEdit(this);      //建立 lineedit 對象
    lineedit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);    //將該對象設爲寬高可擴展
    QLabel* label = new QLabel(this);
    label->setText("請在下方輸入要計算的式子...");  //設置文本內容
    QString btnstr[22] = {"(", ")", "%", "CE", "Del",
                        "7", "8", "9", "+", "-",
                        "4", "5", "6", "*", "/",
                        "1", "2", "3", "More", "=",
                        "0", "."
                       };                       
    auto that = this;
    QPushButton* btn[22];   //建立22個按鈕並用數組儲存,而且綁定相應的槽函數。方便後面佈局(偷懶
    for(int i=0; i<22; i++){
        btn[i] = new QPushButton(that);
        btn[i]->setText(btnstr[i]);
        btn[i]->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        connect(btn[i],&QPushButton::clicked,that,[=](){
            that->input(btnstr[i], lineedit, label);
        });
    }
    
    //設置樣式,美化
    btn[4]->setStyleSheet("color:red;");
    btn[18]->setStyleSheet("color:yellow;");
    int cyellow[9] = {0,1,2,3,8,9,13,14};
    for(int i=0; i<9; i++)  btn[cyellow[i]]->setStyleSheet("color:#38d6d5;");
    lineedit->setStyleSheet("color:#333;font-size:21px;font-weight:bolder;border:1px dashed #f1f1f1;border-radius:5px;text-align:right;");
    label->setStyleSheet("font-size:12px;color:grey;border-bottom:1px solid #f1f1f1;border-radius:5px;text-align:right;");
    lineedit->setAlignment( Qt::AlignRight);
    label->setAlignment( Qt::AlignRight);
    setStyleSheet("QPushButton {font-size:20px;font-weight:bold;color:ligrhtgrey;background-color: rgba(255, 255, 255, 0%);border:1px solid grey;border-radius:5px;} QPushButton:hover, QLabel:hover {font-size:25px;} Widget {background:qlineargradient(spread:pad,y1:1,y2:0,stop:0 #79f4f3,stop:1 #f8fefe);}");
    setWindowTitle("Calculator");
    
    //設置佈局
    QGridLayout* computelayout = new QGridLayout(this);
    computelayout->addWidget(label, 0, 0, 1, 5);
    computelayout->addWidget(lineedit, 1, 0, 1, 5);
    computelayout->addWidget(btn[0], 2, 0, 1, 1);
    computelayout->addWidget(btn[1], 2, 1, 1, 1);
    computelayout->addWidget(btn[2], 2, 2, 1, 1);
    computelayout->addWidget(btn[3], 2, 3, 1, 1);
    computelayout->addWidget(btn[4], 2, 4, 1, 1);
    computelayout->addWidget(btn[5], 3, 0, 1, 1);
    computelayout->addWidget(btn[6], 3, 1, 1, 1);
    computelayout->addWidget(btn[7], 3, 2, 1, 1);
    computelayout->addWidget(btn[8], 3, 3, 1, 1);
    computelayout->addWidget(btn[9], 3, 4, 1, 1);
    computelayout->addWidget(btn[10], 4, 0, 1, 1);
    computelayout->addWidget(btn[11], 4, 1, 1, 1);
    computelayout->addWidget(btn[12], 4, 2, 1, 1);
    computelayout->addWidget(btn[13], 4, 3, 1, 1);
    computelayout->addWidget(btn[14], 4, 4, 1, 1);
    computelayout->addWidget(btn[15], 5, 0, 1, 1);
    computelayout->addWidget(btn[16], 5, 1, 1, 1);
    computelayout->addWidget(btn[17], 5, 2, 1, 1);
    computelayout->addWidget(btn[18], 5, 3, 2, 1);
    computelayout->addWidget(btn[19], 5, 4, 2, 1);
    computelayout->addWidget(btn[20], 6, 0, 1, 2);
    computelayout->addWidget(btn[21], 6, 2, 1, 1);

邏輯設計部分

首先先將每一個按鈕都綁定對應的 槽函數this

//from widget.cpp

    for(int i=0; i<22; i++){
        btn[i] = new QPushButton(that);
        btn[i]->setText(btnstr[i]);
        btn[i]->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        connect(btn[i],&QPushButton::clicked,that,[=](){         //這裏
            that->input(btnstr[i], lineedit, label);
        });
    }

用戶按下 = 按鈕後,利用按鈕的信號和槽調用 input() 函數.net

//from widget.cpp

    void Widget::input(QString word, QLineEdit* lineedit, QLabel* label)
    {
        if(word == "="){
            if(linetxt == "")   label->setText("不能爲空哦...");         // 首先判斷表達式是否合法
            else    compute(lineedit, label);                           //合法,跳轉到計算函數
        }
        else if (word == "More") {              //切換貸款計算界面
            this->hide();
            emit calchangewindow();
        }
        else if (word == "CE") {                //清空
            linetxt = "";
            labeltxt = "";
            label->setText("");
            lineedit->setText(linetxt);
        }
        else if (word == "Del") {               //後退
            QString tmp = "";
            for (int i=0; i < linetxt.length()-1; i++)
                tmp += linetxt[i];
            linetxt = tmp;
            lineedit->setText(linetxt);
        }
        else {
            linetxt+=word;                         //輸入爲字符
            lineedit->setText(linetxt);
        }
    }

計算時咱們須要先將 中綴表達式 轉化爲 後綴表達式設計

中綴表達式就是咱們平常生活中正常使用的那種形如:a+b*c指針

後綴表達式就是形如abc*+,操做符在數字後面;

爲何有後綴表達式呢?

由於中綴表達式便於人們的理解與計算

可是後綴表達式更方便計算機的運算(如二叉樹、堆棧的方法計算)

所以在讀取一箇中綴表達式後,咱們得辦法將他轉化爲後綴表達式。

那麼怎麼轉化爲後綴表達式呢?

咱們能夠用這種方法將中綴表達式轉化爲後綴表達式

如下是節選自項目 backans.cpp 的實現將中綴表達式轉化後綴表達式的函數

//from backans.cpp

    string getback(string str)//獲取後綴表達式的函數
    {
        char* middle = new char[100];
        char* tmp = middle;
        char* isFirst = tmp;
        for (int i=0; i<str.length(); i++) {
            *tmp = str[i];                                    //將 middle 所指向的字符串內容賦值爲傳入的 str ,同時保持 middle 指向首地址不變
            tmp++;
        }
        char* back = new char[100];             //同上
        char* backend = back;
        stack<char> s;
        s.push('#');
        while (*middle)
        {
            if( ((middle == isFirst)&& *middle == '-' && Number(*(middle+1))) || ( *(middle-1) == '(' && *middle == '-' && Number(*(middle+1))) || Number(*middle))
            {
                *back = *middle;                                       //判斷是否爲負數
                back++, middle++;
            }
            else
            {
                if (Number(*(back - 1)))    *back++ = ' ';     //若是前一位是數字的話添加空格 用以區分

                if (*middle == ')')//若是右括號的話,輸出全部操做符直到遇到左括號,並拋棄相對應的一堆括號
                {
                    while (s.top() != '(' && s.top() != '#')
                    {
                        *back = s.top();
                        s.pop();
                        back++;
                            *back++ = ' ';
                    }
                    middle++;
                    s.pop();//拋棄左括號
                }
                else if (*middle == '(')//遇到左括號,則進入棧
                {
                    s.push(*middle); middle++;
                }
                else if (priority(*middle) > priority(s.top()))//若是棧內的操做符優先級高於棧外的優先級,則入棧
                {
                    s.push(*middle); middle++;
                }
                else if (priority(*middle) <= priority(s.top()))
                                                        //若是棧內的操做符優先級低於或等於棧外的優先級,輸出棧內的符號,併入棧棧外的符號
                {
                    while (priority(*middle) <= priority(s.top()) && s.top() != '#') {
                        *back = s.top();
                        back++;                                                                 //直到棧內的操做符爲空 或者 低於棧外的優先級
                        s.pop();
                            *back++ = ' ';
                    }
                    s.push(*middle);
                    middle++;
                }
            }
        }
        while (isOpe(s.top()))//中綴表達式遍歷完成,可是=棧中還有符號存在,一一出棧輸出
        {
            if (Number(*(back - 1)))    *back++ = ' ';
            *back = s.top();
            qDebug("%c",*back);
            s.pop();
            if(s.top() != '#'){
                back++;
                *back++ = ' ';
            }
        }
        string tmpresult = "";                      //後面這些因爲某些蜜汁bug而作出的一些處理。。。請無視充滿了妥協
        string result = "";
        int address = 0;
        for (;backend<=back;backend++)
            tmpresult += *backend;
        while(Number(tmpresult[address]) || isOpe(tmpresult[address]) || tmpresult[address] == ' ')
            result += tmpresult[address++];

        return result;
    }

轉化爲後綴表達式後怎麼計算結果呢?

咱們能夠用這種方法將後綴表達式求值

而後將結果打印至 lineEdit 即完成計算啦!

如下是節選自項目 backans.cpp 的實現計算後綴表達式的函數

//from backans.cpp

    long double backans::result(string str)
    {
        string back = getback(str);
        stack<long double> s;
        for (int i=0; i<back.length(); ) {
            if(!isOpe(back[i]) || (back[i] == '-' && Number(back[i+1]) )){                      //將數字依次入棧
                s.push(turnnum(back, i));
                while (back[i] != ' ')
                    i++;
                i++;
            }
            else {
                long double a = s.top();
                s.pop();
                long double b = s.top();
                s.pop();
                s.push(Cauculate(back[i], b, a));//遇到符號時,取棧頂的第二個數和第一個數求解,併入棧
                i+=2;
            }
        }
        while (s.size() >= 2)//最終棧內存在的數大於2時,繼續計算,直到只剩下一個數
        {
            long double a = s.top();
            s.pop();
            long double b = s.top();
            s.pop();
            s.push(Cauculate(back[back.length()-1], b, a));
        }
        //返回這個數字,既是最終結果
        return s.top();
    }

以上就是所有內容啦,但願能幫到您嘿嘿🤭

項目壓縮包下載地址:https://files-cdn.cnblogs.com/files/Trump-He/Calculator.zip

相關文章
相關標籤/搜索