该项目目标是设计开发一个支持连续计算的包括括号(
)
,求余%
四则运算+
-
*
/
的计算器 Calculator 以及贷款计算功能 Mortgage。
本程序为本人初学一周QT所做,才疏学亦浅,程序中绝对有意想不到的蜜汁bug😆(逃)欢迎你们评论区交流丫。
项目下载地址css
经过单击按钮,输入并完成如4+5.21+6
或 5*(8+16)-2
相似的连续计算,并将运算结果显示在输出文本框 lineEdit
中,计算的式子移至上方的 label
中。
支持负数,小数运算,而且精度为小数点后五位。支持简单的错误性检验。 CE
清空 Del
后退 More
切换至贷款计算。两个界面,贷款计算界面不作过多赘述。c++
Calculator
界面)界面设计部分如图由数组
label
(显示计算的式子)
lineedit
(显示结果或者当前输入的式子)
以及各个按钮组成。ide
建立按钮的时候由于数目有点多,因此咱们能够用数组保存建立的按钮 指针
,后面就能够直接用 索引
对按钮进行操控。函数
QT支持用 css
渲染元素。如label->setStyleSheet("font-size:12px;color:grey;border-bottom:1px solid #f1f1f1;border-radius:5px;text-align:right;");
布局
//from widget.cpp setFixedSize(400,450); //固定窗口大小 setWindowIcon(QIcon(":/icon.png")); //设置icon QLineEdit* lineedit = new QLineEdit(this); //建立 lineedit 对象 lineedit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //将该对象设为宽高可扩展 QLabel* label = new QLabel(this); label->setText("请在下方输入要计算的式子..."); //设置文本内容 QString btnstr[22] = {"(", ")", "%", "CE", "Del", "7", "8", "9", "+", "-", "4", "5", "6", "*", "/", "1", "2", "3", "More", "=", "0", "." }; auto that = this; QPushButton* btn[22]; //建立22个按钮并用数组储存,而且绑定相应的槽函数。方便后面布局(偷懒 for(int i=0; i<22; i++){ btn[i] = new QPushButton(that); btn[i]->setText(btnstr[i]); btn[i]->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); connect(btn[i],&QPushButton::clicked,that,[=](){ that->input(btnstr[i], lineedit, label); }); } //设置样式,美化 btn[4]->setStyleSheet("color:red;"); btn[18]->setStyleSheet("color:yellow;"); int cyellow[9] = {0,1,2,3,8,9,13,14}; for(int i=0; i<9; i++) btn[cyellow[i]]->setStyleSheet("color:#38d6d5;"); lineedit->setStyleSheet("color:#333;font-size:21px;font-weight:bolder;border:1px dashed #f1f1f1;border-radius:5px;text-align:right;"); label->setStyleSheet("font-size:12px;color:grey;border-bottom:1px solid #f1f1f1;border-radius:5px;text-align:right;"); lineedit->setAlignment( Qt::AlignRight); label->setAlignment( Qt::AlignRight); setStyleSheet("QPushButton {font-size:20px;font-weight:bold;color:ligrhtgrey;background-color: rgba(255, 255, 255, 0%);border:1px solid grey;border-radius:5px;} QPushButton:hover, QLabel:hover {font-size:25px;} Widget {background:qlineargradient(spread:pad,y1:1,y2:0,stop:0 #79f4f3,stop:1 #f8fefe);}"); setWindowTitle("Calculator"); //设置布局 QGridLayout* computelayout = new QGridLayout(this); computelayout->addWidget(label, 0, 0, 1, 5); computelayout->addWidget(lineedit, 1, 0, 1, 5); computelayout->addWidget(btn[0], 2, 0, 1, 1); computelayout->addWidget(btn[1], 2, 1, 1, 1); computelayout->addWidget(btn[2], 2, 2, 1, 1); computelayout->addWidget(btn[3], 2, 3, 1, 1); computelayout->addWidget(btn[4], 2, 4, 1, 1); computelayout->addWidget(btn[5], 3, 0, 1, 1); computelayout->addWidget(btn[6], 3, 1, 1, 1); computelayout->addWidget(btn[7], 3, 2, 1, 1); computelayout->addWidget(btn[8], 3, 3, 1, 1); computelayout->addWidget(btn[9], 3, 4, 1, 1); computelayout->addWidget(btn[10], 4, 0, 1, 1); computelayout->addWidget(btn[11], 4, 1, 1, 1); computelayout->addWidget(btn[12], 4, 2, 1, 1); computelayout->addWidget(btn[13], 4, 3, 1, 1); computelayout->addWidget(btn[14], 4, 4, 1, 1); computelayout->addWidget(btn[15], 5, 0, 1, 1); computelayout->addWidget(btn[16], 5, 1, 1, 1); computelayout->addWidget(btn[17], 5, 2, 1, 1); computelayout->addWidget(btn[18], 5, 3, 2, 1); computelayout->addWidget(btn[19], 5, 4, 2, 1); computelayout->addWidget(btn[20], 6, 0, 1, 2); computelayout->addWidget(btn[21], 6, 2, 1, 1);
首先先将每一个按钮都绑定对应的 槽函数this
//from widget.cpp for(int i=0; i<22; i++){ btn[i] = new QPushButton(that); btn[i]->setText(btnstr[i]); btn[i]->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); connect(btn[i],&QPushButton::clicked,that,[=](){ //这里 that->input(btnstr[i], lineedit, label); }); }
用户按下 =
按钮后,利用按钮的信号和槽调用 input()
函数.net
//from widget.cpp void Widget::input(QString word, QLineEdit* lineedit, QLabel* label) { if(word == "="){ if(linetxt == "") label->setText("不能为空哦..."); // 首先判断表达式是否合法 else compute(lineedit, label); //合法,跳转到计算函数 } else if (word == "More") { //切换贷款计算界面 this->hide(); emit calchangewindow(); } else if (word == "CE") { //清空 linetxt = ""; labeltxt = ""; label->setText(""); lineedit->setText(linetxt); } else if (word == "Del") { //后退 QString tmp = ""; for (int i=0; i < linetxt.length()-1; i++) tmp += linetxt[i]; linetxt = tmp; lineedit->setText(linetxt); } else { linetxt+=word; //输入为字符 lineedit->setText(linetxt); } }
计算时咱们须要先将 中缀表达式
转化为 后缀表达式
。设计
中缀表达式就是咱们平常生活中正常使用的那种形如:a+b*c
指针
后缀表达式就是形如abc*+
,操做符在数字后面;
为何有后缀表达式呢?
由于中缀表达式便于人们的理解与计算
可是后缀表达式更方便计算机的运算(如二叉树、堆栈的方法计算)
所以在读取一个中缀表达式后,咱们得办法将他转化为后缀表达式。
那么怎么转化为后缀表达式呢?
咱们能够用这种方法将中缀表达式转化为后缀表达式。
如下是节选自项目 backans.cpp
的实现将中缀表达式转化后缀表达式的函数
//from backans.cpp string getback(string str)//获取后缀表达式的函数 { char* middle = new char[100]; char* tmp = middle; char* isFirst = tmp; for (int i=0; i<str.length(); i++) { *tmp = str[i]; //将 middle 所指向的字符串内容赋值为传入的 str ,同时保持 middle 指向首地址不变 tmp++; } char* back = new char[100]; //同上 char* backend = back; stack<char> s; s.push('#'); while (*middle) { if( ((middle == isFirst)&& *middle == '-' && Number(*(middle+1))) || ( *(middle-1) == '(' && *middle == '-' && Number(*(middle+1))) || Number(*middle)) { *back = *middle; //判断是否为负数 back++, middle++; } else { if (Number(*(back - 1))) *back++ = ' '; //若是前一位是数字的话添加空格 用以区分 if (*middle == ')')//若是右括号的话,输出全部操做符直到遇到左括号,并抛弃相对应的一堆括号 { while (s.top() != '(' && s.top() != '#') { *back = s.top(); s.pop(); back++; *back++ = ' '; } middle++; s.pop();//抛弃左括号 } else if (*middle == '(')//遇到左括号,则进入栈 { s.push(*middle); middle++; } else if (priority(*middle) > priority(s.top()))//若是栈内的操做符优先级高于栈外的优先级,则入栈 { s.push(*middle); middle++; } else if (priority(*middle) <= priority(s.top())) //若是栈内的操做符优先级低于或等于栈外的优先级,输出栈内的符号,并入栈栈外的符号 { while (priority(*middle) <= priority(s.top()) && s.top() != '#') { *back = s.top(); back++; //直到栈内的操做符为空 或者 低于栈外的优先级 s.pop(); *back++ = ' '; } s.push(*middle); middle++; } } } while (isOpe(s.top()))//中缀表达式遍历完成,可是=栈中还有符号存在,一一出栈输出 { if (Number(*(back - 1))) *back++ = ' '; *back = s.top(); qDebug("%c",*back); s.pop(); if(s.top() != '#'){ back++; *back++ = ' '; } } string tmpresult = ""; //后面这些因为某些蜜汁bug而作出的一些处理。。。请无视充满了妥协 string result = ""; int address = 0; for (;backend<=back;backend++) tmpresult += *backend; while(Number(tmpresult[address]) || isOpe(tmpresult[address]) || tmpresult[address] == ' ') result += tmpresult[address++]; return result; }
转化为后缀表达式后怎么计算结果呢?
咱们能够用这种方法将后缀表达式求值。
而后将结果打印至 lineEdit
即完成计算啦!
如下是节选自项目 backans.cpp
的实现计算后缀表达式的函数
//from backans.cpp long double backans::result(string str) { string back = getback(str); stack<long double> s; for (int i=0; i<back.length(); ) { if(!isOpe(back[i]) || (back[i] == '-' && Number(back[i+1]) )){ //将数字依次入栈 s.push(turnnum(back, i)); while (back[i] != ' ') i++; i++; } else { long double a = s.top(); s.pop(); long double b = s.top(); s.pop(); s.push(Cauculate(back[i], b, a));//遇到符号时,取栈顶的第二个数和第一个数求解,并入栈 i+=2; } } while (s.size() >= 2)//最终栈内存在的数大于2时,继续计算,直到只剩下一个数 { long double a = s.top(); s.pop(); long double b = s.top(); s.pop(); s.push(Cauculate(back[back.length()-1], b, a)); } //返回这个数字,既是最终结果 return s.top(); }
以上就是所有内容啦,但愿能帮到您嘿嘿🤭
项目压缩包下载地址:https://files-cdn.cnblogs.com/files/Trump-He/Calculator.zip