计算器程序

第一个Qt程序--计算器,对其做如下介绍

一、功能:

1.多项相加


2.一次计算结束后,计算结果可以继续运算

3.对+,-是作为符号还是运算符的判断


4.清零

    随时可以清零重新计算

5.按下一个数字后,再按下一个或不按运算符,最后按下等号时,计算结果为这个数字本身。

    但是按下一个数字后,按了多个运算符,结果为"Error"


二、实现:

如果只是写两个数进行运算的,其算法很简单,但是对于多项相加的运算,逻辑较复杂一些。核心的计算逻辑主要是用了栈的思想,将多项表达式作两次变化计算结果,即中缀表达式转换为后缀表达式。

其中还有一些较为复杂的逻辑判断,例如判断+,-是作为符号还是运算符等

做了背景,每个按钮做一个小icon,素材是网上下载的图片

背景的实现方法是Qpalette 的setBrush方法

icon是Button的seticon方法


代码如下,大部分已标注里注释

Widget.h文件如下

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QString>
#include <QStack>


namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
    //三个全局变量
    static QString formula;
    static QString tempnum;
    static QString lastres;
    //初始化
    void Init();

    QStack<QString> stk;
    QStringList list;

private slots:
    void onNumBntClicked(int);
    void onSignBntClicked(QString);
    void onEqualBntClicked(bool);
    void onClearBntClicked(bool);

private:
    Ui::Widget *ui;

};

#endif // WIDGET_H

Widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QString>
#include <QSignalMapper>
#include <QStack>
#include <QStringList>
#include <qDebug>
#include <QtMath>

//2.17 1.30 完成基础功能
//2.18 1:50 完成所有功能 还需布置GUI
//2.18 14.28 完成

//检查字符串是否为纯数字,带有符号,小数点
bool Check(QString temp)
{
    int count = 0;
    if( !(temp.at(0)=='.' || temp.at(0)=='+' || temp.at(0)=='-' || (temp.at(0)>='0' && temp.at(0)<='9')) )
        return false;
    for(int i=1;i<temp.size();i++)
    {
        if(temp[i] == '.')
        {
            count++;
            if(count>=2)
                return false;
        }
        else if(!(temp.at(i)>='0' && temp.at(i)<='9' ) )
            return false;
    }
    return true;
}

//静态成员初始化
QString Widget::formula="";
QString Widget::tempnum="";
QString Widget::lastres="";



Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
    ui->setupUi(this);

    Init();
}

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

void Widget::Init()
{
    //给按钮添加图标
    QIcon icon1,icon2,icon3;
    icon1.addFile(tr("F:\\C++ Qt\\sl1.png"));
    icon2.addFile(tr("F:\\C++ Qt\\sl2.png"));
    icon3.addFile(tr("F:\\C++ Qt\\sl3.png"));

    ui->bnt_1->setIcon(icon1);
    ui->bnt_2->setIcon(icon1);
    ui->bnt_3->setIcon(icon1);
    ui->bnt_4->setIcon(icon1);
    ui->bnt_5->setIcon(icon1);
    ui->bnt_6->setIcon(icon1);
    ui->bnt_7->setIcon(icon1);
    ui->bnt_8->setIcon(icon1);
    ui->bnt_9->setIcon(icon1);

    ui->bnt_0->setIcon(icon2);
    ui->bnt_left->setIcon(icon2);
    ui->bnt_right->setIcon(icon2);
    ui->bnt_point->setIcon(icon2);
    ui->bnt_clear->setIcon(icon2);
    ui->bnt_equal->setIcon(icon2);

    ui->bnt_plus->setIcon(icon3);
    ui->bnt_minus->setIcon(icon3);
    ui->bnt_multiply->setIcon(icon3);
    ui->bnt_divided->setIcon(icon3);
    ui->bnt_exp->setIcon(icon3);

    QString sign[7]={"+","-","*","/","(",")","^"};          //运算符数组

    QSignalMapper *numsignal = new QSignalMapper(this);     //数字信号发射器,按不同的数字按钮处理结果不同,其中包括小数点
    QSignalMapper *signsignal = new QSignalMapper(this);    //符号信号发射器,按不同的符号按钮处理结果不同

    QButtonGroup *numgroup = new QButtonGroup(this);        //数字按钮组,储存0~9数字按钮
    QButtonGroup *signgroup = new QButtonGroup(this);       //符号按钮组,储存'+','-','*','/','(',')','^'.

    //将数字按钮插入数字按钮组
    numgroup->addButton(ui->bnt_0,0);
    numgroup->addButton(ui->bnt_1,1);
    numgroup->addButton(ui->bnt_2,2);
    numgroup->addButton(ui->bnt_3,3);
    numgroup->addButton(ui->bnt_4,4);
    numgroup->addButton(ui->bnt_5,5);
    numgroup->addButton(ui->bnt_6,6);
    numgroup->addButton(ui->bnt_7,7);
    numgroup->addButton(ui->bnt_8,8);
    numgroup->addButton(ui->bnt_9,9);
    numgroup->addButton(ui->bnt_point,10);

    //将符号按钮插入符号按钮组
    signgroup->addButton(ui->bnt_plus,1);
    signgroup->addButton(ui->bnt_minus,2);
    signgroup->addButton(ui->bnt_multiply,3);
    signgroup->addButton(ui->bnt_divided,4);
    signgroup->addButton(ui->bnt_left,5);
    signgroup->addButton(ui->bnt_right,6);
    signgroup->addButton(ui->bnt_exp,7);

    //将数字按钮信号与信号发射器相连接
    for(int i=0;i<11;i++)
    {
        QObject::connect(numgroup->button(i),SIGNAL(pressed()),numsignal,SLOT(map()));
        numsignal->setMapping(numgroup->button(i),i);
    }
    QObject::connect(numsignal,SIGNAL(mapped(int)),this,SLOT(onNumBntClicked(int))); //信号发射器与槽连接

    //将符号按钮信号与信号发射器相连接
    for(int i=1;i<8;i++)
    {
        QObject::connect(signgroup->button(i),SIGNAL(pressed()),signsignal,SLOT(map()));
        signsignal->setMapping(signgroup->button(i),sign[i-1]);
    }
    QObject::connect(signsignal,SIGNAL(mapped(QString)),this,SLOT(onSignBntClicked(QString))); //信号发射器与槽连接

    QObject::connect(ui->bnt_equal,SIGNAL(clicked(bool)),this,SLOT(onEqualBntClicked(bool)));//等号按钮,槽与信号的链接
    QObject::connect(ui->bnt_clear,SIGNAL(clicked(bool)),this,SLOT(onClearBntClicked(bool)));//清除按钮,槽与信号的链接
}

void Widget::onNumBntClicked(int a)     //按下数字按钮
{
    lastres.clear();

    if(a>=0 && a<=9)                    //按下的是数点
    {
        formula += QString::number(a);
        tempnum += QString::number(a);
    }
    else                                //按下的是小数点
    {
        tempnum += ".";
        formula += ".";
    }

    ui->output->setText(formula);
}

void Widget::onSignBntClicked(QString tempsign)     //按下符号按钮
{
    if(formula.size()==0 && lastres != "" && lastres != "Error")  //如果直接按了运算符,上一次计算结果不为空
    {
        list<<lastres;
        formula += lastres;
    }                           /* eg:先计算了1+2按下等号后,直接又按了*3,此时再按等号,结果应为9 */

    formula += tempsign;
    if(tempnum != "")           //可能会有连续输入运算符的可能,如 2*(1+2),(-2),此时tempnum为空,不输入进list
        list<<tempnum;

    if( lastres == "" && tempnum=="" && (tempsign=="+" || tempsign=="-") ) //+,-为数字的符号时的情况
        tempnum += tempsign;
    else                                                  //否者 +,-为运算符
    {
        if(stk.isEmpty() || tempsign=="(")  //栈为空或运算符为(,直接入栈
            stk.push(tempsign);
        else if(stk.top()=="(" && (tempsign =="+"||tempsign=="-") && tempnum=="" ) //在括号里输入了一个负数或正数
            tempnum += tempsign;            /* eg: 1+(-2)*3 输入"-"时,此时栈顶比为(,且tempnum为空 */
        else if(stk.top()=="(" && tempsign!=")") //栈顶是(,且输入不是),直接入栈
            stk.push(tempsign);
        else if(tempsign == ")")                 //输入时 )   ,默认前面必有(
        {
            while(stk.top()<"(" || stk.top()>")")   //如果栈顶不为( 或 )  ,有)的情况是多重括号
            {
                QString temp = stk.pop();          //栈顶元素出栈,进入list
                list<<temp;
            }
            stk.pop();
        }
        //不同级别运算符进出栈规则 :将栈内级别大于等于 输入运算符 的运算符输入到list 如果栈为空则停止,最后将输入符号入栈
        else if( tempsign=="+" || tempsign=="-" )
        {

            while(!stk.isEmpty() && stk.top() != "(" ) //一定要先判断栈是否为空,否则如果栈为空了,stk.pop(),stk.top()调用了空指针
            {
                QString temp = stk.pop();
                list<<temp;
            }
            stk.push(tempsign);
        }
        else if( tempsign=="*" || tempsign=="/" )
        {
            while(!stk.isEmpty() && (stk.top()=="*"||stk.top()=="/"||stk.top()=="^"))
            {
                QString temp = stk.pop();
                list<<temp;
            }
            stk.push(tempsign);
        }
        else if(tempsign=="^" )
        {
            while(!stk.isEmpty() && stk.top() == "^")
            {
                QString temp = stk.pop();
                list<<temp;
            }
            stk.push(tempsign);
        }
        else
            stk.push(tempsign);
    }
    if(!(tempnum == "+" || tempnum == "-") && tempres!="") //如果tempnum中的只有+,- 表示当做符号,不清楚
        tempnum.clear();                                      
    ui->output->setText(formula);
}

void Widget::onEqualBntClicked(bool) //按下等号按钮
{
    if(tempnum != "")         //运算符个数为偶数的情况
        list<<tempnum;        /* eg: 1+2+3 在符号按钮里3没有输入到list*/
 
    while(!stk.isEmpty())       //栈内可能会有多余的运算符,输入到list
    {
       QString temp = stk.pop();
       list<<temp;
    }
 
    QString tempres;            //一次运算的结果
    if(list.size()!=0)
    {
        QList<QString>::Iterator it = list.begin();
        if(list.size() <= 2 && *it>="0" && *it<="9"  ) // 只按下一个数字,没有或只按了一个运算符,或只按了运算符
            tempres = *it;  //结果为该数字
 
 
        else if( !( Check(*it) && Check(*(it+1)) ) )  //前两个字符串不为数字,必然是多按了运算符,报错
            tempres = "Error";
        else
        {
            //规则:碰到数字直接入栈;碰到运算符,让栈顶前两个数字做运算,后栈顶元素在运算符前;
            //     将运算结果再次压入栈内
            for(it=list.begin();it!=list.end();it++)    //遍历list
            {
                if(list.startsWith("+"))
                {
                    QString temp1 = stk.pop();
                    QString temp2 = stk.pop();
                    stk.push( QString::number(temp2.toDouble() + temp1.toDouble()) );
                }
                else if(list.startsWith("-"))
                {
                    QString temp1 = stk.pop();
                    QString temp2 = stk.pop();
                    stk.push( QString::number(temp2.toDouble() - temp1.toDouble()) );
                }
                else if(list.startsWith("*"))
                {
                    QString temp1 = stk.pop();
                    QString temp2 = stk.pop();
                    stk.push( QString::number(temp2.toDouble() * temp1.toDouble()) );
                }
                else if(list.startsWith("/"))
                {
                    QString temp1 = stk.pop();
                    QString temp2 = stk.pop();
                    stk.push( QString::number(temp2.toDouble() / temp1.toDouble()) );
                }
                else if(list.startsWith("^"))
                {
                    QString temp1 = stk.pop();
                    QString temp2 = stk.pop();
                    stk.push(QString::number(qPow(temp2.toDouble(),temp1.toDouble())));
                }
                else
                    {stk.push(*it);}
                list.removeFirst();
            }
            tempres = stk.pop(); //最后的栈顶元素为最后计算结果
        }
 
            ui->output_2->setText(formula);
            ui->output->setText(tempres);
 
            lastres = tempres;  //此次计算结果存入lastres
            formula.clear();
            tempnum.clear();
            list.clear();
    }
}
void Widget::onClearBntClicked(bool)
{
    formula.clear();
    tempnum.clear();
    list.clear();
    stk.clear();
    lastres.clear();
    ui->output_2->setText("");
    ui->output->setText("");
}
 

main.cpp

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

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    //添加背景
    w.setAutoFillBackground(true);
    QPalette palette;
    palette.setBrush(QPalette::Background,QBrush(QPixmap("F:\\C++ Qt\\background1.jpg")));
    w.setPalette(palette);
    //题目
    w.setWindowTitle("计算器");

    w.show();

    return a.exec();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值