计算器开发

本文介绍了一个基于QT的计算机软件课设项目,该计算器应用实现了中缀表达式到后缀表达式的转换,并处理了异常输入,如连续小数点。项目使用C++编程,通过双栈方法进行计算,并提供了包括括号、运算符、小数点在内的功能。代码中包含了错误处理,例如检查括号匹配和无效运算分量。
摘要由CSDN通过智能技术生成

一、项目思路

该项目用于计算机软件课设,项目主要解决的部分有:中缀转后缀的处理,异常输入情况如连续输入小数点等等。项目开发中使用的工具是QT。对于中缀转后缀的基本处理思路,我采用双栈法,具体思路见我的这篇文章:利用双栈法实现简易计算器。对于异常输入的这一部分,较为简单,略过。

二、源代码

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <iostream>
#include <QMainWindow>
#include <QDebug>
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private slots:
    void btnnumClicked(); //数字按键点击
    void btnoprClicked(); //运算符符按键点击
    void on_btndel_clicked();
    void btnequClicked(); //等于号点击
    //bool IsPop(char a, char b);
     void InfixToSuffix(char* src, char* des);//中缀表达式变为后缀表达式
  QString calculate(QString s2);
   void btnpointClicked();
   void on_btnAC_clicked();
   void btnbrkClicked();
   void btnfxClicked();
private:
    Ui::MainWindow *ui;
    bool operatorFlag;
    bool waittingForOperand;
    bool frontzero; //前置零 0000.01
    bool pointflag;
    int brkflag;
    bool fxflag;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QStack>
#include<QPushButton>
#include<QMessageBox>
#include<map>
#include<cmath>
#include<QClipboard>
#include<QApplication>
#include<QDebug>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->lineEdit->setAlignment(Qt::AlignRight);
    ui->lineEdit->setText("0");
    this->setWindowTitle("简易科学计算器");
   //参数初始化
    operatorFlag = false;
    //waittingForOperand=false;
    frontzero=true;
    pointflag=false;
    brkflag=0;
    fxflag=false;
    //按键的绑定
        connect(ui->btn0, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn1, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn2, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn3, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn4, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn5, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn6, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn7, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn8, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn9, SIGNAL(clicked()), this, SLOT(btnnumClicked()));

        //符号(加减乘除和括号 以及^
        connect(ui->btnadd, SIGNAL(clicked()), this, SLOT(btnoprClicked()));
        connect(ui->btndiv, SIGNAL(clicked()), this, SLOT(btnoprClicked()));
        connect(ui->btnminus, SIGNAL(clicked()), this, SLOT(btnoprClicked()));
        connect(ui->btnmul, SIGNAL(clicked()), this, SLOT(btnoprClicked()));
        connect(ui->btnplus, SIGNAL(clicked()), this, SLOT(btnoprClicked()));
      //等号
        connect(ui->btnequ, SIGNAL(clicked()), this, SLOT(btnequClicked()));
     //小数点
        connect(ui->btnpoint,SIGNAL(clicked()), this, SLOT(btnpointClicked()));
      //括号
        connect(ui->btnbrk_left,SIGNAL(clicked()), this, SLOT(btnbrkClicked()));
        connect(ui->btnbrk_right,SIGNAL(clicked()), this, SLOT(btnbrkClicked()));

      //函数(单目
     connect(ui->btnsin,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btncos,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btntan,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btnexp,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btnsqrt,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btnln,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btnlg,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
}

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

void MainWindow::btnnumClicked()//数字键显示和储存
{
    QPushButton *buttonClicked = qobject_cast<QPushButton *>(sender());
   int  buttonValue = buttonClicked->text().toInt(); //字符串转为整形
//    if(waittingForOperand)
//    {
//        ui->lineEdit->clear();
//        waittingForOperand = false;
//   }
     QString temp=ui->lineEdit->text(); //获得已输入的文本
     if(temp.right(1)==")")return; //已输入的文本最右端一个字符即最后输入的字符
    if(frontzero)   //如果有前置已有0 防止0000.1
    {
          //移除最后输入0
          if(temp.right(1)=='0')temp.remove(temp.length()-1,1);
          //
          if(buttonValue){
          frontzero = false;
          }
     }
    ui->lineEdit->setText(temp+QString::number(buttonValue));
    operatorFlag=false;
}
void MainWindow::btnpointClicked(){
    QString temp=ui->lineEdit->text();
    if(!pointflag&&'0'<=temp.right(1)&&
            temp.right(1)<='9'){
        ui->lineEdit->setText(ui->lineEdit->text()+".");
        pointflag=true;
        frontzero=false;
        operatorFlag=true;
        fxflag=true;
        return;
    }
}
void MainWindow::btnoprClicked()
{
    QPushButton *buttonClicked = qobject_cast<QPushButton *>(sender());
    if(!operatorFlag){
        QString op=buttonClicked->text();
        ui->lineEdit->setText(ui->lineEdit->text()+op);
        //waittingForOperand=true;
        fxflag=false;
        operatorFlag=true;
        frontzero=true;
        pointflag=false;//加了运算符关于数字的参数都要初始化
    }
    else return;
}

//三角函数调用
void MainWindow::btnfxClicked(){
    if(!fxflag){
 QPushButton *buttonClicked = qobject_cast<QPushButton *>(sender());
 QString tfx=buttonClicked->text();
 QString tle=ui->lineEdit->text();
 if(tle=='0'||tle.right(2)=="(0"){
     if(tle=='0')
     ui->lineEdit->setText(tfx+"("+'0');
     if(tle.right(2)=="(0")
       {
        tle.chop(1);
         ui->lineEdit->setText(tle+tfx+"("+'0');

     }
     brkflag++;
     operatorFlag=false;
     frontzero=true;
     pointflag=false;
     //fxflag=true;
     return;}

 if(('0'<=tle.right(1)&&'9'>=tle.right(1))||tle.right(1)=='.')return;

 ui->lineEdit->setText(tle+tfx+"("+'0');
  brkflag++;
 //waittingForOperand=true;
 operatorFlag=false;
 frontzero=true;
 pointflag=false;
 //fxflag=true;
 return;
    }
    else  return;
}

void MainWindow::btnbrkClicked(){
    QPushButton *buttonClicked = qobject_cast<QPushButton *>(sender());
    //左括号
    if(buttonClicked->text()=='('){
        QString temp=ui->lineEdit->text();
        if( temp.right(1)!='.'&&temp.right(1)!=')'&&
           (temp.right(1)>'9' ||temp.right(1)<'0'))
    {
            ui->lineEdit->setText(temp+"(");
            brkflag++;
            frontzero=false;
            fxflag=false;
    }
        else if(temp=="0"){ui->lineEdit->setText("(");brkflag++;}
    }
    //右括号
    if(buttonClicked->text()==")"){
       if(brkflag<=0)return;
else{
    QString temp_=ui->lineEdit->text();
  if(temp_.right(1)>='0'&&temp_.right(1)<='9'||temp_.right(1)==")")
 {
   ui->lineEdit->setText(temp_+")");
      brkflag--;

}
        }
    }
}


void MainWindow::on_btndel_clicked()
{
    QString text = ui->lineEdit->text();
   operatorFlag=false;
   if(text.right(1)=='.'){pointflag=false;frontzero=true;}
   if(text.right(1)=='(')brkflag--;
   if(text.right(1)==')')brkflag++;

   if(text.right(1)>='a'&&text.right(1)<='z'){
       fxflag=false;
   QString temp= text.right(2);

   if( temp=="os"||temp=="in"||temp=="an"||temp=="xp")
       text.chop(3);
   if( temp=="rt")
       text.chop(4);
   if (temp=="lg"||temp=="ln")
       text.chop(2);
   }
   else text.chop(1);

        if(text.isEmpty())
        {
            text = "0";
            frontzero= true;
        }

        QString tar=text.right(1);
        if(tar<"0"||tar>"9"){

        if(tar>='a'&&tar<='z'){
//            text.append("(0");
           // brkflag++;
            operatorFlag=false;
            frontzero=true;
            pointflag=false;
            fxflag=true;
            }
        else {
            pointflag=operatorFlag=true;
            if(tar!='.')fxflag=false;
            else fxflag=true;
        }
        }
        ui->lineEdit->setText(text);
}



void MainWindow::btnequClicked(){
    if(brkflag){
        QMessageBox::information(this, tr("ERROR!"),
       tr("括号不匹配!"));
        return;
    }
        QString s2 = ui->lineEdit->text();

        if((s2.right(1)<'0'||s2.right(1)>'9')&&s2.right(1)!=')'){
            QMessageBox::information(this, tr("ERROR!"),
           tr("缺少运算分量!"));
           return;
        }


         QString result=calculate(s2);
       ui->lineEdit->setText(result);
       //等于号之后的状态等于输入了一个数字
       //(但没输入运算符 的状态,关于运算符的参数要重置
       operatorFlag=false;
       if(result=='0'){frontzero=true;
           pointflag=false;
           brkflag=0;
           fxflag=false;
       }
       else frontzero=false;
}

void MainWindow::on_btnAC_clicked()
{
    ui->lineEdit->setText("0");
    operatorFlag = false;
   // waittingForOperand=false;
    frontzero=true;
    pointflag=false;
    brkflag=0;
    fxflag=false;
}



/* 中缀转后缀 src带入中缀式,des带出后缀式 */
void MainWindow::InfixToSuffix(char* src, char* des)
{
    std::map<char, int> priority;
    priority['+'] = 0;
    priority['-'] = 0;
    priority['*'] = 1;
    priority['/'] = 1;
    priority['^'] = 2;
    priority['s'] = 3;
    priority['c'] = 3;
    priority['t'] = 3;
    priority['n'] = 3;//ln
    priority['g'] = 3; //lg
    priority['e'] = 3;//exp
    priority['q'] = 3; //sqrt

    des[0]='0';
    des[1]=' ';
    int k = 2;
    /* 符号栈 */
    QStack<char> symbol;

    int i = 0;

    while (src[i] != '\0')
    {

        if (src[i] == ' ')        //如果当前字符是空格,则往后走一个
        {
            i++;
            continue;
        }
        else if (src[i] >= '0' && src[i] <= '9' || src[i] == '.')
        {
            des[k++] = src[i];
            if ((src[i + 1] < '0' || src[i + 1]>'9') && src[i + 1] != '.')        //数字后加空格
            {
                des[k++] = ' ';
            }
        }
        else if (src[i] == '(')    //左括号直接入栈
        {
            symbol.push(src[i]);
        }
        else if (src[i] == ')')    //遇到 ) ,输出( )之间的所有符号
        {
            while (symbol.top() != '(')
            {
                des[k++] = symbol.top();
                des[k++] = ' ';
                symbol.pop();
            }
            symbol.pop();
        }

        /*----------------- 运算符 -------------------------------*/
        else
        {
            switch (src[i])
            {
            case '+':
            case '-':
            case '*':
            case '/':
            case '^':
                if (symbol.empty())        //如果符号栈为空,直接入符号
                {
                    symbol.push(src[i]);
                }
                else                //否则,判断是否选择入符号栈还是出栈顶元素
                {
                    char tempTop = symbol.top();
                    if (tempTop != '(' && priority[src[i]] <= priority[tempTop])    //出符号栈
                    {
                        des[k++] = symbol.top();
                        des[k++] = ' ';
                        symbol.pop();
                        continue;//这是作用于外部循环的continue,这样i就不会加,当前的数跳到else的push操作,再i++
                    }
                    else            //当前符号优先级高,入符号栈
                    {
                        symbol.push(src[i]);
                    }
                }
                break;
            case's'://  sin&sqrt
                if (symbol.empty())        //如果符号栈为空,直接入符号
                {
                    if(src[i+1]=='i')
                    symbol.push(src[i]);
                else
                    symbol.push(src[i+1]);
                }
                else                //否则,判断是否选择入符号栈还是出栈顶元素
                {
                    char tempTop = symbol.top();
                    if(src[i+1]=='i'){
                    if (tempTop != '(' && priority[src[i]] <= priority[tempTop])    //出符号栈
                    {
                        des[k++] = symbol.top();
                        des[k++] = ' ';
                        symbol.pop();
                        continue;
                    }
                    else            //当前符号优先级高,入符号栈
                    {
                        symbol.push(src[i]);
                    }
                    }
                    else {
                        if (tempTop != '(' && priority[src[i+1]] <= priority[tempTop])    //出符号栈
                        {
                            des[k++] = symbol.top();
                            des[k++] = ' ';
                            symbol.pop();
                            continue;
                        }
                        else            //当前符号优先级高,入符号栈
                        {
                            symbol.push(src[i+1]);
                        }
                    }
                }
                if (src[i + 1] == 'i')i += 2;
                else i += 3;
                break;
            case'c':
            case't':
            case'e':
                if (symbol.empty())        //如果符号栈为空,直接入符号
                {
                    symbol.push(src[i]);
                }
                else                //否则,判断是否选择入符号栈还是出栈顶元素
                {
                    char tempTop = symbol.top();
                    if (tempTop != '(' && priority[src[i]] <= priority[tempTop])    //出符号栈
                    {
                        des[k++] = symbol.top();
                        des[k++] = ' ';
                        symbol.pop();
                        continue;
                    }
                    else            //当前符号优先级高,入符号栈
                    {
                        symbol.push(src[i]);
                    }
                }
                i+=2;
                break;
            case'l':
                if (symbol.empty())        //如果符号栈为空,直接入符号
                {
                    symbol.push(src[i+1]);
                }
                else                //否则,判断是否选择入符号栈还是出栈顶元素
                {
                    char tempTop = symbol.top();
                    if (tempTop != '(' && priority[src[i+1]] <= priority[tempTop])    //出符号栈
                    {
                        des[k++] = symbol.top();
                        des[k++] = ' ';
                        symbol.pop();
                        continue;
                    }
                    else            //当前符号优先级高,入符号栈
                    {
                        symbol.push(src[i+1]);
                    }
                }
                i += 1;
                break;

            default:
                i++;
                break;
            }

        }
        i++;
            /* 遍历下一字符 */
    }
    /*字符串已遍历完,把符号栈中剩余的符号入栈到数字栈中 */
    while (!symbol.empty())
    {
        des[k++] = symbol.top();
        des[k++] = ' ';
        symbol.pop();
    }
    des[k] = '\0';
}

QString MainWindow:: calculate(QString s2) {
    QByteArray ba2;
    ba2.append(s2);     //也可以 ba2 = s2.toLatin1();
    char *src = ba2.data();
    char* des = new char[(strlen(src)+1)*3+3];
    InfixToSuffix(src, des);
    QStack<double>num;
    int i = 0;
    while (des[i] != '\0') {
        while (des[i] >= '0' && des[i] <= '9' || des[i] == ' ' || des[i] == '.') {
            if (des[i] != ' ')
            {
                QStack<double>temp;
                double tempnum = 0;
                int n = 1;
                double m = 0.1;
                while (des[i] != ' ' && des[i] != '.') {
                    temp.push((des[i] - '0'));
                    i++;
                }
                if (des[i] == '.') {
                    while (des[++i] != ' ') {
                        double dt = des[i] - '0';
                        tempnum += dt * m;
                        m /= 10;
                    }
                }
                while (!temp.empty()) {
                    tempnum += temp.top() * n;
                    n *= 10;
                    temp.pop();
                }

                num.push(tempnum);
            }
            else i++;
        }
        while (des[i] < '0' || des[i]> '9' || des[i] == ' ')
        {
            double temp1 = 0, temp2 = 0, temp3 = 0;
            switch (des[i++]) {
            case'+':temp1 = num.top();
                num.pop();
                temp2 = num.top();
                num.pop();
                temp3 = temp1 + temp2;
                num.push(temp3);
                break;
            case'-': temp1 = num.top();
                num.pop();
                temp2 = num.top();
                num.pop();
                temp3 = temp2 - temp1;
                num.push(temp3);
                break;
            case'*':temp1 = num.top();
                num.pop();
                temp2 = num.top();
                num.pop();
                temp3 = temp2 * temp1;
                num.push(temp3);
                break;
            case'/': temp1 = num.top();
                num.pop();
                temp2 = num.top();
                num.pop();
                temp3 = temp2 / temp1;
                num.push(temp3);
                break;
            case'^':temp1 = num.top();
                num.pop();
                temp2 = num.top();
                num.pop();
                temp3 =std::pow(temp2,temp1);
                num.push(temp3);
                break;
            case's':temp3 = num.top();
                num.pop();
                temp3 = std::sin(temp3 / 180.0 * M_PI);
                num.push(temp3);
                break;
            case'c':temp3 = num.top();
                num.pop();
                temp3 =std::cos(temp3 / 180.0 * M_PI);
                num.push(temp3);
                break;
            case't':temp3 = num.top();
                num.pop();
                temp3 =std::tan(temp3 / 180.0 * M_PI);
                num.push(temp3);
                 break;
            case'g':temp3 = num.top();
                if(temp3<=0){
                    QMessageBox::information(this, tr("ERROR!"),
                     tr("对数计算分量不能<=0!"));
                return s2;
                }
                num.pop();
                temp3 =std::log10(temp3);
                num.push(temp3);
                break;
            case'n':temp3 = num.top();
                if(temp3<=0){
                    QMessageBox::information(this, tr("ERROR!"),
                     tr("对数计算分量不能<=0!"));
                return s2;
                }
                num.pop();
                temp3 =std::log(temp3);
                num.push(temp3);
                break;
            case'e':temp3 = num.top();
                num.pop();
                temp3 =std::exp(temp3);
                num.push(temp3);
                break;
            case'q':
                temp3 = num.top();
                num.pop();
                temp3 =std::sqrt(temp3);
                num.push(temp3);
                break;
            default:break;
            }
            if (des[i] == '\0')break;
        }
    }
    return QString::number(num.top());
}

main.c

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

三、项目总结

该项目难度较大,尤其是中缀表达式转后缀表达式难以处理,同时要考虑的输入情况较多,我有些情况当时没有考虑到,如对于负数的乘除处理有瑕疵。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值