实验一:简单计算器的开发

目录

一  实验准备

1.编程语言及开发环境的选择

2.实现方法

中缀转后缀,后缀表达式求解

二 实验设计过程

1.界面设计 

 2. 信号与槽的连接

1.信号

2.通过对槽函数的限制实现算数表达式的正确性检验

3. 算法实现

 中缀表达式转后缀表达式

后缀表达式的计算

项目文件结构

 类的定义

 四 测试

 五 打包发布


一  实验准备

1.编程语言及开发环境的选择

本实验采用c++语言qt软件开发。学习路径 最新QT从入门到实战完整版|传智教育_哔哩哔哩_bilibili

2.实现方法

中缀转后缀,后缀表达式求解

1.中缀表达式
中缀表达式是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。在中缀表达式中,运算符具有不同的优先级,并且还可以使用括号改变运算的次序,因此运算规律比较复杂,不适于计算机求解表达式。

2.后缀表达式
后缀表达式,即逆波兰式。
我们平时写的a+b是中缀表达式,写成后缀表达式就是:ab+
特点:
1)后缀表达式的操作数与中缀表达式的操作数先后次序相同,而运算符的先后次序不同;
2)后缀表达式中没有括号,而且运算符没有优先级;
3)后缀表达式计算过程严格按照从左到右的顺序进行。

3.算法思路

I 中缀表达式转后缀表达式

设置一个运算符栈,用来存放运算符。
定义一个字典,保存优先级。

从左向右依次读取算术表达式的元素X,分以下情况进行不同的处理:

(1)如果X是操作数,直接入队

(2)如果X是运算符,再分以下情况:  a)如果栈为空,直接入栈。  b)如果X==”(“,直接入栈。  c)如果X==”)“,则将栈里的元素逐个出栈,并入队到后缀表达式队列中,直到第一个配对的”(”出栈。(注:“(”和“)”都不 入队)       d)如果是其他操作符(+ - * /),则和栈顶元素进行比较优先级。 如果栈顶元素的优先级大于等于X,则出栈并把栈中弹出的元素入队,直到栈顶元素的优先级小于X或者栈为空。弹出完这些元素后,才将遇到的操作符压入到栈中。

(3)最后将栈中剩余的操作符全部入队。

II  后缀表达式求解

首先准备一个栈Res_Stack.

1、从左开始向右遍历后缀表达式的元素。

2、如果取到的元素是操作数,直接入栈Res_Stack,如果是运算符,从栈中弹出2个数进行运算,然后把运算结果入栈

3、当遍历完后缀表达式时,计算结果就保存在栈里了。

二 实验设计过程

1.界面设计 

 

 font: bold 14px;
    padding: 6px;
background-color: rgb(30, 155, 144)

 21个PushButton,1个Label 和设置相应的格式

历史记录面板


//展开历史对话框
void Widget::on_Button_history_clicked()
{
    if(isOpen==false){
        history_dia.show();
        isOpen=true;
    }
    else if(isOpen==true){
        history_dia.close();
        isOpen=false;
    }
}
//将结果添加到“历史”对话框的最后并换行
    history_dia.ui->textBrowser->setText
            (history_dia.ui->textBrowser->document()->toPlainText()+expression+"="+QString::number(Ans)+"\n");

 2. 信号与槽的连接

1.信号

private slots:
    void on_Button_1_clicked();

    void on_Button_2_clicked();

    void on_Button_3_clicked();

    void on_Button_4_clicked();

    void on_Button_5_clicked();

    void on_Button_6_clicked();

    void on_Button_8_clicked();

    void on_Button_7_clicked();

    void on_Button_9_clicked();

    void on_Button_add_clicked();

    void on_Button_0_clicked();

    void on_Button_point_clicked();

    void on_Button_subtract_clicked();

    void on_Button_multiply_clicked();

    void on_Button_divide_clicked();

    void on_Button_clear_clicked();

    void on_Button_back_clicked();

    void on_Button_equal_clicked();

    void on_Button_left_clicked();

    void on_Button_right_clicked();

    void on_Button_history_clicked();

2.通过对槽函数的限制实现算数表达式的正确性检验

(1)当钱输入是0到9时,如果上个符号是右括号则不输入数字
void Widget::on_Button_1_clicked()
{  int i=expression.length()-1;
    if(expression .length()==0){
        Expression += "1";
        expression += "1";
        ui->Screen->setText(expression);
    }
      else if(expression.at(i) == ")")
      {
         ui->Screen->setText(expression);
               }
    else{
    Expression += "1";
    expression += "1";
    ui->Screen->setText(expression);}
}

void Widget::on_Button_2_clicked()
{
    int i=expression.length()-1;
    if(expression .length()==0){
        Expression += "2";
        expression += "2";
        ui->Screen->setText(expression);
    }
      else if(expression.at(i) == ")")
      {
         ui->Screen->setText(expression);
               }
       else{
       Expression += "2";
       expression += "2";
       ui->Screen->setText(expression);}
}

void Widget::on_Button_3_clicked(){
    int i=expression.length()-1;
    if(expression .length()==0){
        Expression += "3";
        expression += "3";
        ui->Screen->setText(expression);
    }
      else if(expression.at(i) == ")")
      {
         ui->Screen->setText(expression);
               }
       else{
       Expression += "3";
       expression += "3";
       ui->Screen->setText(expression);}
}

void Widget::on_Button_4_clicked()
{
    int i=expression.length()-1;
    if(expression .length()==0){
        Expression += "4";
        expression += "4";
        ui->Screen->setText(expression);
    }
      else if(expression.at(i) == ")")
      {
         ui->Screen->setText(expression);
               }
       else{
       Expression += "4";
       expression += "4";
       ui->Screen->setText(expression);}
}

void Widget::on_Button_5_clicked()
{
    int i=expression.length()-1;
    if(expression .length()==0){
        Expression += "5";
        expression += "5";
        ui->Screen->setText(expression);
    }
      else if(expression.at(i) == ")")
      {
         ui->Screen->setText(expression);
               }
       else{
       Expression += "5";
       expression += "5";
       ui->Screen->setText(expression);}
}

void Widget::on_Button_6_clicked()
{
    int i=expression.length()-1;
    if(expression .length()==0){
        Expression += "6";
        expression += "6";
        ui->Screen->setText(expression);
    }
      else if(expression.at(i) == ")")
      {
         ui->Screen->setText(expression);
               }
       else{
       Expression += "6";
       expression += "6";
       ui->Screen->setText(expression);}
}

void Widget::on_Button_8_clicked(){
    int i=expression.length()-1;
    if(expression .length()==0){
        Expression += "8";
        expression += "8";
        ui->Screen->setText(expression);
    }
      else if(expression.at(i) == ")")
      {
         ui->Screen->setText(expression);
               }

       else{
       Expression += "8";
       expression += "8";
       ui->Screen->setText(expression);}
}

void Widget::on_Button_7_clicked()
{  int i=expression.length()-1;
    if(expression .length()==0){
        Expression += "7";
        expression += "7";
        ui->Screen->setText(expression);
    }
      else if(expression.at(i) == ")")
      {
         ui->Screen->setText(expression);
               }

       else{
       Expression += "7";
       expression += "7";
       ui->Screen->setText(expression);}
}

void Widget::on_Button_9_clicked()
{
    int i=expression.length()-1;
    if(expression .length()==0){
        Expression += "9";
        expression += "9";
        ui->Screen->setText(expression);
    }
      else if(expression.at(i) == ")")
      {
         ui->Screen->setText(expression);
               }
       else{
       Expression += "9";
       expression += "9";
       ui->Screen->setText(expression);}
}

void Widget::on_Button_add_clicked()
{int i =expression .length() - 1;
    if(expression .length()==0|| expression.at(i) == "(" ){
    Expression += "0~+~";
    expression += "+";
    ui->Screen->setText(expression);}
    else if (expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
    {
        ui->Screen->setText(expression);
    }
    else{
        Expression += "~+~";
        expression += "+";
        ui->Screen->setText(expression);
    }
}

void Widget::on_Button_0_clicked()
{
    int i=expression.length()-1;
    if(expression .length()==0){
        Expression += "0";
        expression += "0";
        ui->Screen->setText(expression);
    }
      else if(expression.at(i) == ")")
      {
         ui->Screen->setText(expression);
               }
       else{
       Expression += "0";
       expression += "0";
       ui->Screen->setText(expression);}
}

(2)对小数点的正确性检验,如果多个小数点则只输入一个,如果前面又括号和操作符,则不输入,如果小数点前无数字,则在小数点前补0

//如果当前按钮是 ‘.’如果前面有括号操作符小数点什么也不做
void Widget::on_Button_point_clicked()
{//如果小数点前无数字,则补0
  int i =expression .length() - 1;
        if(expression.length()==0||(expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/"|| expression.at(i) == "(" )){
        Expression += "0.";
        expression += ".";
        ui->Screen->setText(expression);
   }
       //如果是右括号则不输入
        else if(expression.at(i) == ")"||expression.at(i) == ".")
        {
            ui->Screen->setText(expression);
        }
         //如果数字中有了小数点,则不输入
       else {
                  int falg1=0;//设置标志
                  int j;
                  //判断字符中是否有".",j为数字首字符串位置
                  for( j=expression .length() - 1;j>0;j--){
                      if(expression.at(j) == "+"|| expression.at(j) == "-" || expression.at(j) == "*" || expression.at(j) == "/"|| expression.at(j) == "(" || expression.at(j) == ")")
                           break;
                  }
                  //判断数字字符串是否已经有"."
                  for(int t=expression .length() - 1;t>j;t--)
                      if(expression.at(t) == "."){
                          falg1=1;
                      }
                  //如果有则什么也不输出
                  if(falg1==1){
                          ui->Screen->setText(expression);
                  }
                  //否则输出点
                  else{
                      Expression += ".";
                      expression += ".";
                     ui->Screen->setText(expression);
                  }
              }
}

(3)加减乘除输入的正确性检验 ,如果前面无输入或者时左括号则补0 ,连续输入运算符,则不输入

void Widget::on_Button_add_clicked()
{int i =expression .length() - 1;
    if(expression .length()==0|| expression.at(i) == "(" ){//如果前面无输入或者时左括号则补0
    Expression += "0~+~";
    expression += "+";
    ui->Screen->setText(expression);}
    //连续输入运算符,则不输入
    else if (expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
    {
        ui->Screen->setText(expression);
    }
    else{
        Expression += "~+~";
        expression += "+";
        ui->Screen->setText(expression);
    }
}
void Widget::on_Button_subtract_clicked()
{int i =expression .length() - 1;
    if(expression.length()==0|| expression.at(i) == "(" ){
    Expression += "0~-~";
    expression += "-";
    ui->Screen->setText(expression);
    }
    else if (expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
    {
        ui->Screen->setText(expression);
    }
    else{
        Expression += "~-~";
        expression += "-";
        ui->Screen->setText(expression);
    }
}

void Widget::on_Button_multiply_clicked()
{
       int i =expression .length() - 1;
        if(expression.length()==0|| expression.at(i) == "(" ){
        Expression += "1~*~";
        expression += "*";
        ui->Screen->setText(expression);
        }
        else if (expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
        {
            ui->Screen->setText(expression);
        }
        else{
            Expression += "~*~";
            expression += "*";
            ui->Screen->setText(expression);
        }
}

void Widget::on_Button_divide_clicked()
{

    int i =expression .length() - 1;
     if(expression.length()==0||expression.at(i) == "("){//如果前面无输入或者时左括号不输入
     ui->Screen->setText(expression);
     }
     else if (expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
     {
         ui->Screen->setText(expression);
     }
     else{
         Expression += "~/~";
         expression += "/";
         ui->Screen->setText(expression);
     }
}

(4)等号事件响应  空字符和缺少操作数不输出 补全右括号 把结果加到历史记录里,并输出算术表达式和结果

//等号按钮点击事件
void Widget::on_Button_equal_clicked()
{   //空字符输入 缺少操作数则不输入,也不输出
    int i=expression.length()-1;
    if (expression.length() == 0||expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
   {
        return;
    }
    else if(expression.length() != 0){
    //补全右括号
    int count1=0;
    int count2=0;
    for(int j=expression .length() - 1;j>=0;j--){
        if(expression.at(j)=="("){
            count1++;
        }
      else if(expression.at(j)==")"){
            count2++;
        }
    }
    if(count1>count2){
        int t=count1-count2;
        while(t>0){
            expression += ")";
            Expression += "~)~";
            t--;
        }
    }
    }
    //将Expression分割,存入字符串数组ex中。ex最后一位为"#"
    QStringList ex=Expression.split("~");
    ex.insert(ex.length(),"#");
    //计算
    double Ans=this->Run(this->Transform(ex));

    //将结果添加到“历史”对话框的最后并换行
    history_dia.ui->textBrowser->setText
            (history_dia.ui->textBrowser->document()->toPlainText()+expression+"="+QString::number(Ans)+"\n");
    //将两个E/expression归零
    expression.clear();
    Expression.clear();
}

(5)括号限制输入,如果上一个是数字和右括号则当前左括号不输入,如果上一个是运算符,括号是,则当前右括号不输入。如果当前算数表达式中左括号的数量小于等于右括号的数量,则当前右括号不输入。

//左括号限制输入
void Widget::on_Button_left_clicked()
{
    int i;
    i=expression .length();
if(expression.length()==0){
    expression += "(";
    Expression += "~(~";
    ui->Screen->setText(expression);
}


else if(expression.at(i-1) == "+"|| expression.at(i-1) == "-" || expression.at(i-1) == "*" || expression.at(i-1) == "/"||expression.at(i-1) == "(")
        {
    expression += "(";
    Expression += "~(~";
    ui->Screen->setText(expression);
}

else{
    ui->Screen->setText(expression);
}
}
//右括号限制输入

void Widget::on_Button_right_clicked()
{
   // int flag1=0;
    int i=expression.length();
    int count1=0;
    int count2=0;
    for(int j=expression .length() - 1;j>=0;j--){
        if(expression.at(j)=="("){
            count1++;
        }
      else  if(expression.at(j)==")"){
            count2++;
        }
    }
    if(expression.length()==0){
        ui->Screen->setText(expression);
    }
   else if(expression.at(i-1) == "+"|| expression.at(i-1) == "-" || expression.at(i-1) == "*" || expression.at(i-1) == "/"||expression.at(i-1)==")"||expression.at(i-1)=="("){

            ui->Screen->setText(expression);
        }
    else if(count1>count2){
        expression += ")";
        Expression += "~)~";
        ui->Screen->setText(expression);
    }

}

3. 算法实现

 中缀表达式转后缀表达式

//中缀转换成后缀表达式
QStringList Widget::Transform(QStringList ex){

    QStack<QString> stack;
    stack.push("#");
    QString r;

    QStringList anssss;

    for(int i=0;!stack.isEmpty();){
        //如果ex[i]是操作数,则存入r中,直到遇到操作符为止。
        if(ex[i]!="+"&&ex[i]!="-"&&ex[i]!="*"&&ex[i]!="/"&&ex[i]!="%"
                &&ex[i]!="("&&ex[i]!=")"&&ex[i]!="#"){
            anssss.insert(i,ex[i]);
            i++;

        }
        //遇到了操作符时:
        else {


            //接下来处理操作符ex[i]

            //若栈外操作符ex[i]优先级大于栈内操作符stack.top()优先级,则ex[i]进栈
            if(icp(ex[i])>isp(stack.top())){
                stack.push(ex[i]);
                i++;
            }

            //若栈外操作符优先级小于栈内操作符优先级,则将栈内操作符输出到后缀表达式,并出栈。
            else if(icp(ex[i])<isp(stack.top()))
            {
                QString x=stack.top();
                anssss.insert(i,x);
                stack.pop();
            }
            //若栈外栈内优先级相同,退栈不输出。同时,如果栈内是“(“,则读取下一字符
            else if(icp(ex[i])==isp(stack.top())){
                QString pop=stack.top();
                stack.pop();
                if(pop=="(")
                    i++;
            }
        }
    }
    return anssss;
}

后缀表达式的计算

 //取出两个操作数
    bool Widget::GetOperand(double& left,double& right){
        right=s.top();
        s.pop();
        left=s.top();
        s.pop();
    }
//开始计算
double Widget::Run(QStringList exx){
    int i=0;double l,r;
    while(i<exx.length()){
        if(exx[i]!=""&&exx[i]!="+"&&exx[i]!="-"&&exx[i]!="*"&&exx[i]!="/"){
            //操作数进栈
            s.push(exx[i].toDouble());
            i++;
        }
        else if(exx[i]!=""){
            if(exx[i]=="+"){
                this->GetOperand(l,r);
                s.push(l+r);
                i++;
            }
            else if(exx[i]=="-"){
                this->GetOperand(l,r);
                s.push(l-r);
                i++;
            }
            else if(exx[i]=="*"){
                this->GetOperand(l,r);
                s.push(l*r);
                i++;
            }
            else if(exx[i]=="/"){
                this->GetOperand(l,r);
                s.push(l/r);
                i++;
            }


        }
        else{
            i++;
        }
    }

    double ans=s.top();
    s.pop();
    //将“历史”对话框中的label文本改变。
    history_dia.ui->label->setText("历史记录:");
    ui->Screen->setText(expression+"="+QString::number(ans));
    return ans;
}

项目文件结构

 类的定义

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QString>
#include <QStack>
#include <QDialog>
#include "history.h"
#include <QIcon>


namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();
    void paintEvent(QPaintEvent *event);

private slots:
    void on_Button_1_clicked();

    void on_Button_2_clicked();

    void on_Button_3_clicked();

    void on_Button_4_clicked();

    void on_Button_5_clicked();

    void on_Button_6_clicked();

    void on_Button_8_clicked();

    void on_Button_7_clicked();

    void on_Button_9_clicked();

    void on_Button_add_clicked();

    void on_Button_0_clicked();

    void on_Button_point_clicked();

    void on_Button_subtract_clicked();

    void on_Button_multiply_clicked();

    void on_Button_divide_clicked();

    void on_Button_clear_clicked();

    void on_Button_back_clicked();

    void on_Button_equal_clicked();

    void on_Button_left_clicked();

    void on_Button_right_clicked();

    void on_Button_history_clicked();
private:
    Ui::Widget *ui;

    //储存两个表达式
    QString expression;
    QString Expression;

    //建立“历史记录”对话框的对象
    history history_dia;
    //判断“历史记录”对话框是否打开
    bool isOpen;
private:
    //下面的函数可以将中缀表达式转换为后缀表达式

    //运算符s位于栈外的优先级
    int icp(QString s);

    //运算符s位于栈内的优先级
    int isp(QString s);

    //将分割后的字符串作为参数,返回后缀表达式。
    QStringList Transform(QStringList ex);


    //实现后缀表达式的计算
private:
    QStack<double> s;

    //开始计算
    double Run(QStringList exx);

    //计算当前运算符ch
    void calculate(char ch);

    //从栈中取出两个操作数left和rigth
    bool GetOperand(double& left,double& right);



};

#endif // WIDGET_H

四 测试

简单计算器测试

 五 打包发布

参考视频最新QT从入门到实战完整版|传智教育_哔哩哔哩_bilibili

 

 打包完成。


版权声明:本文为qq_57577960原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。