项目一 :简单计算器的实现

  预习日志


1.1 项目目标和主要内容
1 )学习图形界面的设计,利用 MFC 应用程序( Java swing QT
框架,或 C# )创建基于对话框的应用程序,添加按钮、编辑框等控件;
2 )能通过设计的按钮控件输入并实现简单算术运算,要求表达式在
编辑框中显示,能将运算结果,输出在编辑框内显示;并保存历史的表
达式运算记录。
3 )也能够实现混合运算的算术表达式求解,算术表达式中包括加、
减、乘、除、括号等运算符;并且能够识别括号,优先级正确。
1.2 项目的主要功能
1 )计算器能够实现混合运算的算术表达式求解;
2 )输入时有足够的容错机制,来尽量避免用户输入不合规的算术表
达式
1.3项目具体思路

1 设置窗口大小以及缓冲区大小

2 绘制整体界面

3 采用字符串保存数字字符

4 清空输入 输出区字符

5 其他功能 回退,清空,等于

代码实现

calculator.h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include<QPushButton>
#include<QLineEdit>
#include<QHBoxLayout>
#include<QVBoxLayout>
#include<QGridLayout>
#include<QString>
#include<QStack>
#include<QTime>
#include<iterator>
class calculator : public QMainWindow
{
    Q_OBJECT

public:
    calculator(QWidget *parent = 0);
    ~calculator();

private:
      QLineEdit *inputLine;
    QLineEdit *historyList;

      QString input="0"; 
      bool flat=false;

      QPushButton *zeroButton;
      QPushButton *oneButton;
      QPushButton *twoButton;
      QPushButton *threeButton;
      QPushButton *fourButton;
      QPushButton *fiveButton;
      QPushButton *sixButton;
      QPushButton *sevenButton;
      QPushButton *eightButton;
      QPushButton *nineButton;


      QPushButton *addButton;
      QPushButton *subButton;
      QPushButton *divButton;
      QPushButton *mulButton;
      QPushButton *equButton;
      QPushButton *decButton;
      QPushButton *botButton;

      QPushButton *CEButton;
      QPushButton *ACButton;
      QPushButton *CButton;
      QPushButton *lefButton;
      QPushButton *rigButton;

private slots:

      void buttonZeroClicked();
      void buttonOneClicked();
      void buttonTwoClicked();
      void buttonThreeClicked();
      void buttonFourClicked();
      void buttonFiveClicked();
      void buttonSixClicked();
      void buttonSevenClicked();
      void buttonEightClicked();
      void buttonNineClicked();


      void buttonAddClicked();
      void buttonSubClicked();
      void buttonMulClicked();
      void buttonDivClicked();
      void buttonDecClicked();
      void buttonBotClicked(); 

      void buttonEquClicked();

      void buttonLefClicked();
      void buttonRigClicked();

      void buttonCEClicked();
      void buttonCClicked();
      void buttonACClicked();
};

#endif // MAINWINDOW_H

calculator.cpp文件

#include "calculator.h"
#include<iostream>
using namespace std;
#include<stack>
#include<vector>
#include<cstdlib>
#include<limits.h>
#pragma execution_character_set("utf-8")
bool isNum(char ch);
bool isOperate(char ch);
int level(char ch);
double scd(string s);
double getValue(vector<string> V);
vector<string> midToPost(string s);

calculator::calculator(QWidget *parent) : QMainWindow(parent)
{


       QWidget *widget=new QWidget;
       this->setCentralWidget(widget);

       inputLine=new QLineEdit;
       inputLine->setText(input);
       historyList = new QLineEdit;

       zeroButton=new QPushButton("0");
       oneButton=new QPushButton("1");
       twoButton=new QPushButton("2");
       threeButton=new QPushButton("3");
       fourButton=new QPushButton("4");
       fiveButton=new QPushButton("5");
       sixButton=new QPushButton("6");
       sevenButton=new QPushButton("7");
       eightButton=new QPushButton("8");
       nineButton=new QPushButton("9");
       decButton=new QPushButton(".");

       addButton=new QPushButton("+");
       subButton=new QPushButton("-");
       mulButton=new QPushButton("*");
       divButton=new QPushButton("/");
       equButton=new QPushButton("=");

       lefButton=new QPushButton("(");
       rigButton=new QPushButton(")");
       CEButton=new QPushButton("CE");
       ACButton=new QPushButton("AC");
        CButton=new QPushButton("C");

       QGridLayout *H=new QGridLayout(this);

       inputLine->setFixedHeight(50);
     historyList->setFixedHeight(50);

       H->addWidget(inputLine,0,0,1,5);
       H->addWidget(historyList,5,0,1,4);
       H->setRowStretch(0,100);
       CButton->setFixedHeight(50);



       H->addWidget(oneButton,1,0);
       H->addWidget(twoButton,1,1);
       H->addWidget(threeButton,1,2);
       H->addWidget(CEButton,1,3);
       H->addWidget(ACButton,1,4);

       H->addWidget(fourButton,2,0);
       H->addWidget(fiveButton,2,1);
       H->addWidget(sixButton,2,2);
       H->addWidget(addButton,2,3);
       H->addWidget(subButton,2,4);

       H->addWidget(sevenButton,3,0);
       H->addWidget(eightButton,3,1);
       H->addWidget(nineButton,3,2);
       H->addWidget(mulButton,3,3);
       H->addWidget(divButton,3,4);

       H->addWidget(zeroButton,4,0);
       H->addWidget(decButton,4,1);
       H->addWidget(lefButton,4,2);
       H->addWidget(rigButton,4,3);
       H->addWidget(equButton,4,4);
          H->addWidget(CButton,5,4);

       widget->setLayout(H);

       connect(zeroButton,SIGNAL(clicked()),this,SLOT(buttonZeroClicked()));
       connect(oneButton,SIGNAL(clicked()),this,SLOT(buttonOneClicked()));
       connect(twoButton,SIGNAL(clicked()),this,SLOT(buttonTwoClicked()));
      connect(threeButton,SIGNAL(clicked()),this,SLOT(buttonThreeClicked()));
       connect(fourButton,SIGNAL(clicked()),this,SLOT(buttonFourClicked()));
       connect(fiveButton,SIGNAL(clicked()),this,SLOT(buttonFiveClicked()));
       connect(sixButton,SIGNAL(clicked()),this,SLOT(buttonSixClicked()));
       connect(sevenButton,SIGNAL(clicked()),this,SLOT(buttonSevenClicked()));
       connect(eightButton,SIGNAL(clicked()),this,SLOT(buttonEightClicked()));
       connect(nineButton,SIGNAL(clicked()),this,SLOT(buttonNineClicked()));

       connect(addButton,SIGNAL(clicked()),this,SLOT(buttonAddClicked()));
       connect(subButton,SIGNAL(clicked()),this,SLOT(buttonSubClicked()));
       connect(mulButton,SIGNAL(clicked()),this,SLOT(buttonMulClicked()));
       connect(divButton,SIGNAL(clicked()),this,SLOT(buttonDivClicked()));



       connect(decButton,SIGNAL(clicked(bool)),this,SLOT(buttonDecClicked()));

       connect(lefButton,SIGNAL(clicked(bool)),this,SLOT(buttonLefClicked()));
       connect(rigButton,SIGNAL(clicked(bool)),this,SLOT(buttonRigClicked()));

       connect(CEButton,SIGNAL(clicked()),this,SLOT(buttonCEClicked()));
       connect(ACButton,SIGNAL(clicked()),this,SLOT(buttonACClicked()));
       connect(CButton,SIGNAL(clicked()),this,SLOT(buttonCClicked()));

       connect(equButton,SIGNAL(clicked()),this,SLOT(buttonEquClicked()));

}

void calculator::buttonZeroClicked()
{
    if(input=="0")
    input='0';
    else input=input+'0';
    inputLine->setText(input);
}

void calculator::buttonOneClicked()
{
    if(input=="0")
    input='1';
    else input=input+'1';
    inputLine->setText(input);
}

void calculator::buttonTwoClicked()
{
    if(input=="0")
    input='2';
    else input=input+'2';
    inputLine->setText(input);
}

void calculator::buttonThreeClicked()
{
    if(input=="0")
    input='3';
    else input=input+'3';
    inputLine->setText(input);
}

void calculator::buttonFourClicked()
{
    if(input=="0")
    input='4';
    else input=input+'4';
    inputLine->setText(input);
}

void calculator::buttonFiveClicked()
{
    if(input=="0")
    input='5';
    else input=input+'5';
    inputLine->setText(input);
}

void calculator::buttonSixClicked()
{
    if(input=="0")
    input='6';
    else input=input+'6';
    inputLine->setText(input);
}

void calculator::buttonSevenClicked()
{
    if(input=="0")
    input='7';
    else input=input+'7';
    inputLine->setText(input);
}

void calculator::buttonEightClicked()
{
    if(input=="0")
    input='8';
    else input=input+'8';
    inputLine->setText(input);
}

void calculator::buttonNineClicked()
{
    if(input=="0")
    input='9';
    else input=input+'9';
    inputLine->setText(input);
}

void calculator::buttonAddClicked()
{
    if(input=="0")
    input='+';
    else input=input+'+';
    inputLine->setText(input);
}

void calculator::buttonSubClicked()
{
    if(input=="0")
    input='-';
    else input=input+'-';
    inputLine->setText(input);
}

void calculator::buttonMulClicked()
{
    if(input=="0")
    input='*';
    else input=input+'*';
    inputLine->setText(input);
}

void calculator::buttonDivClicked()
{
    if(input=="0")
    input='/';
    else input=input+'/';
    inputLine->setText(input);
}



void calculator::buttonDecClicked()
{
    if(input=="0")
    input='.';
    else input=input+'.';
    inputLine->setText(input);
}

void calculator::buttonBotClicked()
{
      if(input=="0")
        input='-';
      else
      {
      QString::iterator p=input.end();
        p--;
        if('-'==*p)
        input=input.left(input.length()-1);
        else input=input+'-';
     }
     inputLine->setText(input);
}

void calculator::buttonLefClicked()
{
    if(input == "0")
    {
        input = "(";
    }
    else
    {


        char lastChar = input.back().toLatin1();



        if(lastChar == '+' || lastChar == '-' || lastChar == '*' || lastChar == '/'||lastChar=='('||lastChar==')')
        {
            input = input + "(";
        }
        else
        {

            input = input + "=syntax error";
            inputLine->setText(input);
            return;
        }
    }

    inputLine->setText(input);
}


void calculator::buttonRigClicked()
{
    if(input == "0")
    {
        input = ")";
    }
    else
    {

        char lastChar = input.back().toLatin1();

        if(isNum(lastChar)||lastChar=='('||lastChar==')')
        {
            input = input + ")";
        }
        else
        {

            input = input + "=syntax error";
            inputLine->setText(input);
            return;
        }
    }
    inputLine->setText(input);
}


void calculator::buttonCEClicked()
{
    input = input.left(input.length()-1);
    inputLine->setText(input);
}
void calculator::buttonACClicked()
{
    input = "0";
    inputLine->setText(input);
}

void calculator::buttonCClicked()
{
     historyList->clear();
}

void calculator::buttonEquClicked()
{
    string inputTemp = input.toStdString();
    vector<string> expression = midToPost(inputTemp);
    double value = getValue(expression);
    if(value != INT_MAX)
    {
        input = input + "=" + QString::number(value);
        inputLine->setText(input);
        QString history = historyList->text();
        if(history.isEmpty())
  {
       historyList->setText(input);
  }
  else
  {
      historyList->setText(history + "\n" + input);
  }
}
    else { input = input + "=syntax error"; inputLine->setText(input);
    }
}

bool isNum(char ch)
{
    if(ch >= '0' && ch <= '9') return true;
    else return false;
}

bool isOperate(char ch)
{
    if(ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')')
    return true;
    else return false;
}

int level(char ch)
{
    switch(ch)
    {
        case '(' :
            return 5;
        case '*' :
            return 4;
        case '/' :
            return 4;
        case '+' :
            return 3;
        case '-' :
            return 3;
        case ')':
            return 2;
    }
}

double scd(string s)
{
    if(s.length() == 0) return INT_MAX;

    bool flag = false;
    for(int i = 0; i < s.length(); i++)
    {
        if(i == 0 && s[i] == '-') continue;
        else if(s[i] == '.' && !flag)
        {
            if(i > 0 && isNum(s[i-1]))
            {
                flag = true;
                continue;
            }
            else return INT_MAX;
        }
        else if(isNum(s[i])) continue;
        else return INT_MAX;
    }

    double result = atof(s.c_str());
    return result;
}


vector<string> midToPost(string s)
{
    stack<char> S;
    vector<string> V;
    int i = 0;
    while(i < s.length())
    {
        if(isNum(s[i]))
        {
            string str = "";
            while(isNum(s[i]) || s[i] == '.')
            {
                str += s[i];
                i++;
            }
            V.push_back(str);
        }

        else if(isOperate(s[i]))
        {

            if(s[i] == '-' && (i == 0 || !isNum(s[i-1])))
            {
                string str = "-"; i++;
                while(isNum(s[i]) || s[i] == '.')
                {
                    str += s[i]; i++;
                }
                V.push_back(str);
            }
            else
            {
                if(S.empty())
                {
                    S.push(s[i]); i++;
                }
                else
                {
                    int initial = level(s[i]);
                    if(initial == 2)
                    {
                        while(level(S.top()) != 5 && !s.empty())
                        {
                            string str = "";
                            str += S.top();
                            V.push_back(str);
                            S.pop();
                        }
                        if(S.top() == '(') S.pop();
                        i++;
                    }


                    else
                    {
                        while(!S.empty() && initial <= level(S.top()) && level(S.top()) != 5)
                        {
                            string str = "";
                            str += S.top();
                            V.push_back(str);
                            S.pop();
                        }
                        S.push(s[i]); i++;
                    }
                }
            }
        }
        else
        {
            cout << "表达式出错" << endl;
            V.clear();
            return V;
        }
    }
    while(!S.empty())
    {
        string str = ""; str += S.top();
        S.pop();
        V.push_back(str);
    }
    //for(int i = 0; i < V.size(); i++) cout << V[i] << "[]";
    return V;
}


double getValue(vector<string> V)
{
    stack<double> S;
    for(int i = 0; i < V.size(); i++)
    {
        if(V[i].length() == 1 && isOperate(V[i][0]))
        {
            double a = 0, b = 0;
            if(!S.empty())
            {
                a = S.top();
                S.pop();
            }else return INT_MAX;

            if(!S.empty())
            {
                b = S.top();
                S.pop();
            }else return INT_MAX;

            switch(V[i][0])
            {
                case '+':
                    S.push(b+a);
                    break;
                case '-':
                    S.push(b-a);
                    break;
                case '*':
                    S.push(b*a);
                    break;
                case '/':
                    S.push(b/a);
                    break;
                default:
                    return INT_MAX;
            }
        }
        else
        {
            if(scd(V[i]) == INT_MAX) return INT_MAX;
            else S.push(scd(V[i]));
        }
    }
    if(S.empty()) return INT_MAX;

    double value = S.top();
    S.pop();
    return value;
}

calculator::~calculator()
{

}

运行结果:

点击C清除历史记录

以及报错处理

double scd(string s)
{
    if(s.length() == 0) return INT_MAX;

    bool flag = false;
    for(int i = 0; i < s.length(); i++)
    {
        if(i == 0 && s[i] == '-') continue;
        else if(s[i] == '.' && !flag)
        {
            if(i > 0 && isNum(s[i-1]))
            {
                flag = true;
                continue;
            }
            else return INT_MAX;
        }
        else if(isNum(s[i])) continue;
        else return INT_MAX;
    }

    double result = atof(s.c_str());
    return result;
}

这段代码实现的是将一个字符串转化为 double 类型的数值。函数的参数是一个字符串类型的变量 s,表示需要转化的字符串。

函数首先检查字符串长度是否为0,如果是,则返回一个最大值为 INT_MAX 的数值。

然后,函数遍历字符串中的每一个字符,做如下判断:

  1. 如果字符是负号并且是第一个字符,则跳过该字符,继续检查下一个字符。

  2. 如果字符是小数点并且之前没有出现过小数点,则继续检查下一个字符。

  3. 如果字符是数字,则继续检查下一个字符。

  4. 如果字符不是上述三种情况,则字符串中包含非法字符,返回一个最大值为 INT_MAX 的数值。

如果字符串中没有非法字符,则函数使用 atof 函数将字符串转化为 double 类型的数值,并返回这个数值。

vector<string> midToPost(string s)
{
    stack<char> S;
    vector<string> V;
    int i = 0;
    while(i < s.length())
    {
        if(isNum(s[i]))
        {
            string str = "";
            while(isNum(s[i]) || s[i] == '.')
            {
                str += s[i];
                i++;
            }
            V.push_back(str);
        }

        else if(isOperate(s[i]))
        {

            if(s[i] == '-' && (i == 0 || !isNum(s[i-1])))
            {
                string str = "-"; i++;
                while(isNum(s[i]) || s[i] == '.')
                {
                    str += s[i]; i++;
                }
                V.push_back(str);
            }
            else
            {
                if(S.empty())
                {
                    S.push(s[i]); i++;
                }
                else
                {
                    int initial = level(s[i]);
                    if(initial == 2)
                    {
                        while(level(S.top()) != 5 && !s.empty())
                        {
                            string str = "";
                            str += S.top();
                            V.push_back(str);
                            S.pop();
                        }
                        if(S.top() == '(') S.pop();
                        i++;
                    }


                    else
                    {
                        while(!S.empty() && initial <= level(S.top()) && level(S.top()) != 5)
                        {
                            string str = "";
                            str += S.top();
                            V.push_back(str);
                            S.pop();
                        }
                        S.push(s[i]); i++;
                    }
                }
            }
        }
        else
        {
            cout << "表达式出错" << endl;
            V.clear();
            return V;
        }
    }
    while(!S.empty())
    {
        string str = ""; str += S.top();
        S.pop();
        V.push_back(str);
    }
    //for(int i = 0; i < V.size(); i++) cout << V[i] << "[]";
    return V;
}

这段代码实现了将中缀表达式转换为后缀表达式的功能。函数接受一个字符串 s,其中包含中缀表达式,返回一个字符串数组 vector<string>,其中为转换后的后缀表达式。

  1. 遍历字符串 s,如果遇到数字,将数字及其可能的小数点连续取出,放入 vector<string> V 中,表示该数字。
  2. 如果遇到运算符号,分为如下情况处理: a. 如果当前运算符是负号 "-",且它前面没有数字或者前面的字符不是数字或括号,则它是一个负数的符号,需要将其作为数字的一部分,连同负数后面的数字一起取出,放入 vector<string> V 中。 b. 如果当前运算符不是负号,需要考虑其与栈中已有运算符的优先级,如果栈顶运算符的优先级高于等于当前运算符,需要将栈顶运算符弹出,并放入 vector<string> V 中,直到栈顶元素优先级低于当前运算符或栈顶为左括号 "(",此时将当前运算符压入栈中。
  3. 如果遇到非数字和运算符的字符,说明表达式存在格式错误,直接返回空的 vector<string> V。
  4. 遍历结束后,如果栈中还有元素,需要将其弹出并放入 vector<string> V 中,得到最终的后缀表达式。

最后,程序返回 vector<string> V,其中包含转换后的后缀表达式。

double getValue(vector<string> V)
{
    stack<double> S;
    for(int i = 0; i < V.size(); i++)
    {
        if(V[i].length() == 1 && isOperate(V[i][0]))
        {
            double a = 0, b = 0;
            if(!S.empty())
            {
                a = S.top();
                S.pop();
            }else return INT_MAX;

            if(!S.empty())
            {
                b = S.top();
                S.pop();
            }else return INT_MAX;

            switch(V[i][0])
            {
                case '+':
                    S.push(b+a);
                    break;
                case '-':
                    S.push(b-a);
                    break;
                case '*':
                    S.push(b*a);
                    break;
                case '/':
                    S.push(b/a);
                    break;
                default:
                    return INT_MAX;
            }
        }
        else
        {
            if(scd(V[i]) == INT_MAX) return INT_MAX;
            else S.push(scd(V[i]));
        }
    }
    if(S.empty()) return INT_MAX;

    double value = S.top();
    S.pop();
    return value;
}

从左往右遍历后缀表达式,如果遇到运算符,则从栈中取出上一个操作数(先取出的是第二个操作数,后取出的是第一个操作数),进行运算,并将结果压入栈中;如果遇到数字,则将其转化为 double 类型并压入栈中。如果在遍历过程中栈为空,则说明表达式有错误,返回 INT_MAX。

其中,isOperate 函数用于判断一个字符是否为运算符;scd 函数用于将一个字符串转化为数字,如果无法转化则返回 INT_MAX。如果遇到未知的运算符,也返回 INT_MAX。

最后,如果栈中只有一个元素,则为计算结果。将其取出并返回。如果栈中有多个元素,则说明表达式有错误,返回 INT_MAX。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值