Qt实现简易计算器

最近没事在学习Qt,做了一个简易计算器的小设计。记录在此,方便大家,也方便自己。

一、整体方案设计
本设计总体可分为两个部分,界面设计部分和内部逻辑部分。下面分别进行讲解。

二、界面设计部分:
界面设计
界面设计入上图所示一些按钮和一个QLineEdit(用于输入数字和显示结果)和QLabel(用于显示运算表达式)。
本部分主要是采用界面设计师(直接拖拽设计)和代码设计部分。其中代码设计部分主要是为了完成图中所示的布局。具体的代码如下所示:

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{


    ui->setupUi(this);

    connect(this,&Widget::SendOpe,this,&Widget::RecOpe);
    connect(this,&Widget::SendNum,this,&Widget::RecNum);

    setFixedSize(this->width(), this->height());        //禁止改变窗口大小

    //设置布局
    QVBoxLayout *layout1 = new QVBoxLayout();
    layout1->addWidget(ui->label_show_exp);

    layout1->addWidget(ui->lineEdit) ;


    QGridLayout *layout = new QGridLayout();
    layout->addWidget(ui->pushButton_CE,0,0,1,1);
    layout->addWidget(ui->pushButton_C,0,1,1,1);
    layout->addWidget(ui->pushButton_bac,0,2,1,3);

    layout->addWidget(ui->pushButton_7,1,0,1,1);
    layout->addWidget(ui->pushButton_8,1,1,1,1);
    layout->addWidget(ui->pushButton_9,1,2,1,1);
    layout->addWidget(ui->pushButton_add,1,3,1,1);
    layout->addWidget(ui->pushButton_lef,1,4,1,1);

    layout->addWidget(ui->pushButton_4,2,0,1,1);
    layout->addWidget(ui->pushButton_5,2,1,1,1);
    layout->addWidget(ui->pushButton_6,2,2,1,1);
    layout->addWidget(ui->pushButton_sub,2,3,1,1);
    layout->addWidget(ui->pushButton_rig,2,4,1,1);

    layout->addWidget(ui->pushButton_1,3,0,1,1);
    layout->addWidget(ui->pushButton_2,3,1,1,1);
    layout->addWidget(ui->pushButton_3,3,2,1,1);
    layout->addWidget(ui->pushButton_mul,3,3,1,1);


    layout->addWidget(ui->pushButton_0,4,0,1,2);
    layout->addWidget(ui->pushButton_poi,4,2,1,1);
    layout->addWidget(ui->pushButton_div,4,3,1,1);

    layout->addWidget(ui->pushButton_equ,3,4,2,1);

    layout1->addLayout(layout);
    setLayout(layout1);

    setWindowTitle(tr("简易计算器"));        //设置程序标题

    ui->lineEdit->setText("0");        //初始化
    flag = 0;       //括号标志

    //设置背景,按钮透明等样式
    SetSty();

}

代码分析:以上代码主要是完成了界面的布局。基本上外部的垂直布局里面套了个网格布局(网格布局里主要是处于下方的按钮)。
还有SetSty()函数主要是为了突出一些逼格,重新包装了一下整个程序,其实也就是设置了下背景,按钮样式之类。包装之后的界面入下图所示:
界面设计

三、逻辑设计部分
逻辑设计部分主要又包括两个部分:一是保证输入正确的表达式。二是计算正确的表达式。
(1)保证输入正确的表达式。这里既包括输入数字和运算符,也包括正确输入他们的关系。
其中,前者,主要是利用按钮的信号和槽,即按下一个数字,将会触发一个槽,在这个槽中输入这个数字。具体的,在本程序中为了程序的简洁化,中间又加了一个公共的信号,这样按下任意一个数字都会触发同样的信号SendNum(int num)。这个信号有一个参数,就是对应的数字值。同理,符号也是一样。具体代码(后面粘贴的代码也有涉及)如下:

void Widget::on_pushButton_7_clicked()
{
    emit SendNum(7);        //发送输入数字7信号
}
void Widget::on_pushButton_add_clicked()
{
    emit SendOpe('+');          //发送输入加号 信号
}
//接收输入数字信号需要进行的操作
void Widget::RecNum(int num)
{
    QString input_num = ui->lineEdit->text();

    if(input_num == "0")
    {
        ui->lineEdit->setText(QString::number(num));          //去掉前导0,并添加num
    }
    else
    {
        if(input_num[0]=='A' || input_num[0] == 'T')           //上一次结果的第一个字符(An 或者An或者The)
        {
            ui->lineEdit->clear();
            ui->label_show_exp->clear();
        }

        ui->lineEdit->insert(QString::number(num));          //在末尾插入数字num
    }

    ui->lineEdit->setFocus ();      //继续追加光标
}


对于后者,再输入的时候主要有一下要考虑的:
(a)、浮点数的正确输入。(如 :“0.3…2”就不合法)
(b)、左右括号要匹配。( 如:“3+)))”) 肯定有问题)
©、 左括号前面是运算符或者左括号,后面是数字或者左括号;右括号前面是数字或者右括号,右括号后面是运算符或者右括号。(如:“((33+)、(8+2)3”等输入不正确 )
(d)、本程序每次输入运算符或者右括号时提交数字。

基本的代码如下(上面粘贴的代码也有涉及):


//接收输入运算符信号需要进行的操作
void Widget::RecOpe(QChar ch)
{
    QString input_num0 = ui->lineEdit->text();      //获取输入的字符串

    QString ori_exp = ui->label_show_exp->text();      //获取显示板上的字符串

    if(ori_exp.isEmpty() == false)      //提交字符串不为空时
    {
        if(input_num0.isEmpty() == true)       //输入数字为空
        {
            int length = ori_exp.size();

            if(ori_exp[length-1] != ')')       //不等于右括号才能,改变输入错误的运算符号
            {
                ori_exp.replace(length-1,1,QString(ch));
                ui->label_show_exp->setText(ori_exp);
            }
            else
            {
                ui->label_show_exp->setText(ori_exp+QString(ch));       //提交运算符
            }

        }
        else
        {
            int length = ori_exp.size();

            if(ori_exp[length-1] != ')')       //不等于右括号才能加入运算符和数字
            {
                //将输入的数字和运算符提取出来,然后输出至显示板
                QRegExp rx;
                rx.setPattern("(\\.){0,1}0+$");
                bool ok;
                QString input_num = QString("%1").arg(input_num0.toDouble(&ok),0,'f',-1).replace(rx,"");
                QString input_inf = input_num+QString(ch);
                ui->label_show_exp->setText(ori_exp+input_inf);
            }
            else       //只能加入运算符
            {
                 ui->label_show_exp->setText(ori_exp+QString(ch));
            }
        }

        ui->lineEdit->clear();
       ui->lineEdit->setFocus ();       //取回焦点
    }       //已经提交(在显示板上显示的)的字符串为空
    else
    {
        if(input_num0.isEmpty() == false)
        {
            QRegExp rx;
            rx.setPattern("(\\.){0,1}0+$");

            bool ok;
            QString input_num = QString("%1").arg(input_num0.toDouble(&ok),0,'f',-1).replace(rx,"");
            QString input_inf = input_num+QString(ch);
            ui->label_show_exp->setText(ori_exp+input_inf);
        }

        ui->lineEdit->clear();
       ui->lineEdit->setFocus ();
    }
}

(2)、计算正确输入的表达式:本程序采用的过程是先把中序表达式转化为后续表达式,然后利用后续表达式进行计算。其中的原理网上很多,在此就不赘述了。涉及到的主要代码如下:

//获取后缀表达式
int Widget::GetPostExp(QString exp_str,QString pos_exp[])
{

    int pos_exp_top = 0;

    QChar opes_temp[MAXSIZE];       //存放临时符号栈
    int opes_temp_top = 0;
    opes_temp[opes_temp_top++] = QChar('#');

    int length = exp_str.size();

    for(int i = 0;i<length;++i)
    {
        if(exp_str[i].isDigit())    //提取数字串
        {
            int beg = i;
            while(i<length)
            {
                if(exp_str[i].isDigit() || exp_str[i] == '.')
                    ++i;
                else
                    break;
            }
            pos_exp[pos_exp_top++] = exp_str.mid(beg,i-beg);

            i = i-1;

        }
        else       //提取运算符串
       {
            int pri_i = GetPriOfOpe(exp_str[i],1);      //入栈优先级

            while(opes_temp_top >= 0)
            {
                QChar ch_top = opes_temp[opes_temp_top-1];
                int pri_j = GetPriOfOpe(ch_top,0);      //出栈优先级

                if(pri_j >= pri_i)
                {
                     --opes_temp_top;        //栈递减

                    if(ch_top != '(')
                        pos_exp[pos_exp_top++] = QString(ch_top);       //入后缀表达式
                    else
                         break;      //右括号匹配到左括号,退出
                }
                else
                    break;
            }
            if(exp_str[i] != ')')
                opes_temp[opes_temp_top++] = exp_str[i];        //入暂时栈
       }

     }

    //将剩余的栈中元素装入后缀表达式
    for(int i = opes_temp_top-1;i>0;--i)
         pos_exp[pos_exp_top++] = QString(opes_temp[i]);
    return pos_exp_top;
}

//根据字符串计算数值
double Widget::CalFromStr(QString exp_str,bool &ok)
{
    QString pos_exp[MAXSIZE];
    int num = GetPostExp(exp_str,pos_exp);

    double nums[num];
    int nums_top = 0;
    ok = true;      //运算成功
    for(int i = 0;i<num;++i)
    {
        QString temp = pos_exp[i];

        if(temp[0].isDigit() == true)       //数字
        {
            nums[nums_top++] = temp.toDouble();
        }
        else
        {
            //出栈两个运算数
            double sec_num = nums[--nums_top];
            double fir_num = nums[--nums_top];
            double ans = 0;

            if(temp[0] == '+')
            {
                ans = fir_num+sec_num;
            }
            else if(temp[0] == '-')
            {
                  ans = fir_num- sec_num;
            }
            else if(temp[0] == '*')
              {
                 ans = fir_num*sec_num;
            }
            else
            {
                if(sec_num == 0)
                {
                     ok = false;
                     return -1;     //运算失败
                }
                else
                    ans = fir_num/sec_num;
            }

             nums[nums_top++] = ans;     //计算后结果入栈
        }
    }

    return nums[0];

}

四、设计结果
设计结果
基本的设计结果如上。可以进行+、-、*、/以及带括号的相关计算。并没有画太多时间在这个上面,如果有错误,还请大家指针。

具体的源码以及整个工程见:点这儿

  • 28
    点赞
  • 208
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值