# Calculator **Repository Path**: bubbleloo/Calculator ## Basic Information - **Project Name**: Calculator - **Description**: DT QT Calculator - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2020-05-28 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Calculator ![UI](.\pic\UI.png) ### 1 新建工程 ### 2 新建界面类CalculatorUI CalculatorUI.h ```C++ #ifndef CALCULATORUI_H #define CALCULATORUI_H #include #include #include class CalculatorUI : public QWidget { Q_OBJECT private: QLineEdit* m_edit; QPushButton* m_buttons[20]; CalculatorUI(); // 第一阶构造函数, 私有函数 bool construct(); // 第二阶构造函数, 私有函数, UI界面代码在这个函数实现 public: static CalculatorUI* NewInstance(); // 创建实例, 使用到二阶构造函数 void show(); protected slots: void onButtonClicked(); }; #endif // CALCULATORUI_H ``` CalculatorUI.cpp , 创建UI界面。 CalculatorUI::CalculatorUI() : QWidget(NULL, Qt::WindowCloseButtonHint) 设置窗口样子只有关闭按钮。 m_edit->setAlignment(Qt::AlignRight); // 设置行编辑器右边对齐 QPushButton* btn = dynamic_cast(sender()); // 将发送对象转换为强制类型转换为QPushButton类型 ```C++ #include "CalculatorUI.h" #include CalculatorUI::CalculatorUI() : QWidget(NULL, Qt::WindowCloseButtonHint) { } bool CalculatorUI::construct() { bool ret = true; const char* btnText[20] = { "7","8","9","+","(", "4","5","6","-",")", "1","2","3","*","<-", "0",".","=","/","C", }; /* 创建行编辑器 */ m_edit = new QLineEdit(this); if ( m_edit!=NULL ) { m_edit->move(10,10); m_edit->resize(240,30); m_edit->setReadOnly(true); m_edit->setAlignment(Qt::AlignRight); // 设置右边对齐 } else { ret = false; } /* 创建按钮4*5 */ for (int i=0; (i<4)&&ret; i++) // 有4行 { for (int j=0;j<5;j++) // 每行有5列 { int k = 5*i+j; m_buttons[k] = new QPushButton(this); if (m_buttons[k]!=NULL) { m_buttons[k]->resize(40,40); m_buttons[k]->move(10+(10+40)*j,50+(10+40*i)); // 第一个按钮位置为(10,50), 按钮的横向和纵向空间都为10 m_buttons[k]->setText(btnText[k]); connect(m_buttons[k],SIGNAL(clicked(bool)), this, SLOT(onButtonClicked())); } else { ret = false; } } } return ret; } CalculatorUI *CalculatorUI::NewInstance() { CalculatorUI* ret = new CalculatorUI(); if ( ret == NULL || !ret->construct() ) { delete ret; ret = NULL; } return ret; } void CalculatorUI::show() { QWidget::show(); setFixedSize(width(), height()); } void CalculatorUI::onButtonClicked() { QPushButton* btn = dynamic_cast(sender()); // 获取发送者 if (btn!=NULL) { QString text = m_edit -> text(); qDebug() << "button " << btn->text(); m_edit->setText(text + btn->text()); } } ``` ### 3 应用框架 ![Calculator应用框架](.\pic\Calculator应用框架.png) ICalculator.h ``` #ifndef ICALCULATOR_H #define ICALCULATOR_H #include class ICalculator { public: virtual bool expression(const QString exp) = 0; virtual QString result() = 0; }; #endif // ICALCULATOR_H ``` Caclulator类包含用户界面CalculatorUI和业务逻辑CalculatorDec,关系为组合关系,是整体与部分关系,不可分开。 CalculatorDec实现接口ICalculator。 CalculatorUI和ICalculator为聚合关系,CalculatorUI成员中m_cal为指向ICalculator接口实现对象的指针。用户界面类CalculatorUI中成员函数m_cal指向用户逻辑类CalculatorDec。 ```C++ // CalculatorUI.h class CalculatorUI : public QWidget { Q_OBJECT protected: ICalculator* m_cal; /* 接口 */ private: QLineEdit* m_edit; QPushButton* m_buttons[20]; CalculatorUI(); // 第一阶构造函数, 私有函数 bool construct(); // 第二阶构造函数, 私有函数, UI界面代码在这个函数实现 public: static CalculatorUI* NewInstance(); // 创建实例, 使用到二阶构造函数 void show(); // Calculator interface public method ICalculator* getCalculator(); void setCalculator(ICalculator* cal); protected slots: void onButtonClicked(); }; // CalculatorUI.cpp CalculatorUI::CalculatorUI() : QWidget(NULL, Qt::WindowCloseButtonHint) { m_cal = NULL; } void CalculatorUI::onButtonClicked() { QPushButton* btn = dynamic_cast(sender()); // 获取发送者(按键) if ( btn != nullptr ) { QString clickText = btn->text(); if(clickText=="<-") { QString text = m_edit->text(); if (text.length()>0) { text.remove(text.length()-1,1); m_edit->setText(text); } } else if(clickText=="C") { m_edit->setText(""); } else if(clickText=="=") { /* 使用接口,m_cal由上一级类指定设置 */ if (m_cal!=NULL) { m_cal->expression(m_edit->text()); m_edit->setText(m_cal->result()); } } else { m_edit->setText(m_edit->text()+clickText); } } } ICalculator *CalculatorUI::getCalculator() { return m_cal; } void CalculatorUI::setCalculator(ICalculator *cal) { m_cal = cal; } ``` CalculatorDec.h ```C++ #ifndef CALCULATORDEC_H #define CALCULATORDEC_H #include #include #include #include "ICalculator.h" class CalculatorDec : public ICalculator { protected: QString m_result; bool isDigitOrDot(QChar c); bool isOperator(QString c); bool isSymbol(QChar c); bool isSign(QChar c); bool isNumber(QString s); bool isLeft(QString s); bool isRight(QString s); int priority(QString s); bool match(QQueue exp); QQueue split(const QString exp); // split the expression and get the operator and operand bool transform(QQueue exp, QQueue &output); // transform to postfix expression QString calculate(QString l,QString op,QString r); QString calculate(QQueue& exp); public: CalculatorDec(); // implement interface bool expression(const QString exp) override; QString result() override; }; #endif // CALCULATORDEC_H ``` CalculatorDec.cpp ```C++ #include "CalculatorDec.h" #include CalculatorDec::CalculatorDec() : m_result("") { #if 0 // test QQueue r = split("-9+(3.1-1)*5.3"); for (int i=0;i output; transform(r,output); for(int i=0;i exp) { bool ret = true; int len = exp.length(); QStack stack; for ( int i=0;i -9 3 1 - 5 + 算法:以符号作为标志对表达式的字符逐个访问 - 定义累计变量num - 当前字符exp[i]为数字或小数点时: 累计: num+=exp[i] - 当前字符exp[i]为符号时: num为运算数,分离并保存到队列 若exp[i]为正负号: 累计符号为+和-:num+=exp[i] 若exp[i]为运算付: 分离并保存到队列 */ QQueue CalculatorDec::split(const QString exp) { QQueue ret; QString num = ""; QString pre = ""; /* for each QChar in exp */ for (int i=0;i exp, QQueue &output) { bool ret = match(exp); QStack stack; output.clear(); while ( ret && !exp.isEmpty() ) { QString e = exp.dequeue(); if ( isNumber(e) ) // 若为数字则入队 { output.enqueue(e); } else if ( isOperator(e) ) // 若为操作符 { /* 1 与栈顶运算符进行优先级比较 2 小于等于:将栈顶元素输出,转步骤1 3 大于:将当前元素e入栈 */ while ( !stack.isEmpty() && (priority(e)<=priority(stack.top())) ) { output.enqueue( stack.pop() ); } stack.push(e); } else if ( isLeft(e) ) // 若为左括号则入栈 { stack.push(e); } else if ( isRight(e) ) // 若为右括号则出栈 { /* 1 弹出栈顶元素并输出直至栈顶元素为左括号 2 将栈顶的左括号从栈中弹出 */ while ( !stack.isEmpty() && !isLeft(stack.top()) ) { output.enqueue(stack.pop()); } if ( !stack.isEmpty() ) { stack.pop(); } } else { ret = false; } } while (!stack.isEmpty()) { output.enqueue(stack.pop()); } if (!ret) // 出错则输出也要清空 { output.clear(); } return ret; } QString CalculatorDec::calculate(QString l, QString op, QString r) { QString ret = "Error"; if ( isNumber(l) && isNumber(r) ) { double lp = l.toDouble(); double rp = r.toDouble(); if ( op=="+") { ret = QString::asprintf("%f",lp+rp); } else if ( op=="-" ) { ret = QString::asprintf("%f",lp-rp); } else if ( op=="*" ) { ret = QString::asprintf("%f",lp*rp); } else if ( op=="/" ) { const double P=0.00000001; if (-P &exp) { QString ret = "Error"; QStack stack; while( !exp.isEmpty() ) { QString e = exp.dequeue(); if ( isNumber(e) ) { stack.push(e); } else if ( isOperator(e) ) { QString rp = !stack.isEmpty() ? stack.pop() : ""; QString lp = !stack.isEmpty() ? stack.pop() : ""; QString result = calculate(lp,e,rp); if ( result != "Error" ) { stack.push(result); } else { break; } } else { break; } } if ( exp.isEmpty() && (stack.size()==1) && isNumber(stack.top()) ) { ret = stack.pop(); } return ret; } bool CalculatorDec::expression(const QString exp) { bool ret = false; QQueue spExp = split(exp); QQueue postExp; if ( transform(spExp,postExp) ) { m_result = calculate(postExp); ret = (m_result!="Error"); } else { m_result = "Error"; } return ret; } QString CalculatorDec::result() { return m_result; } ``` Caclulator类 Calculator.h ```C++ #ifndef CALCULATOR_H #define CALCULATOR_H #include "CalculatorUI.h" #include "CalculatorDec.h" class Calculator { protected: CalculatorUI* m_ui; CalculatorDec m_cal; Calculator(); bool construct(); public: static Calculator* NewInstance(); void show(); ~Calculator(); }; #endif // CALCULATOR_H ``` Calculator.cpp ```C++ #include "Calculator.h" Calculator::Calculator() { } bool Calculator::construct() { m_ui = CalculatorUI::NewInstance(); // 初始化用户界面类 if ( m_ui!=NULL ) { m_ui->setCalculator(&m_cal); // 设置业务逻辑实现类 } return (m_ui!=NULL); } Calculator* Calculator::NewInstance() { Calculator* ret = new Calculator(); if ( ret==NULL || !ret->construct() ) { delete ret; ret = NULL; } return ret; } void Calculator::show() { m_ui->show(); } Calculator::~Calculator() { } ``` main.cpp ```C++ #include #include "Calculator.h" int main(int argc, char *argv[]) { int ret = -1; QApplication a(argc, argv); Calculator* cal = Calculator::NewInstance(); if (cal!=NULL) { cal->show(); ret = a.exec(); delete cal; } return ret; } ```