主要使用Qt Creator设计计算器,方法采用中缀表达式转后缀表达式;
main.h
#include <QtGui>
#include <QtWidgets>
#include "QCalculatorUI.h"
#include "QCalculatorDec.h"
int main(int argc, char* argv[])
{
/*设置字体为GBK*/
QTextCodec *codec = QTextCodec::codecForName("GBK");
QTextCodec::setCodecForLocale(codec);
QApplication app(argc,argv);
QCalculatorUI* ui = QCalculatorUI::NewIntance();
if(ui==NULL)
return false;
ui->show();
return app.exec();
}
前缀转后缀
1.分离前缀
QQueue<QString> QCalculatorDec::Split(const QString& exp) //分离前缀
{
QQueue<QString> ret;
QString num="";
for(int i=0;i<exp.length();i++)
{
if( (exp[i]=='.') || ( (exp[i]>='0') && (exp[i]<='9') )) //判断小数点和数字
{
num += exp[i];
}
else if(exp[i]== '(' || exp[i]== ')' || exp[i]== '*' || exp[i]== '/' )
{
if(!num.isEmpty())
{
ret.enqueue(num); //将数字入队列
num.clear();
}
ret.enqueue(exp[i]);
}
else if(exp[i]== '+' || exp[i]== '-') // + - 需要特殊处理
{
if(i==0) //表达式开头,说明是正负号
{
num+= exp[i];
}
else if(exp[i-1]=='(' || exp[i-1]=='+' || exp[i-1]=='-' || exp[i-1]=='*' || exp[i-1]=='/')
{
num+= exp[i];
}
else //否则是加减运算符
{
if(!num.isEmpty())
{
ret.enqueue(num); //将数字入队列
num.clear();
}
ret.enqueue(exp[i]);
}
}
}
if(!num.isEmpty()) //遍历完成,判断是否还有数字
{
ret.enqueue(num);
num.clear();
}
return ret;
}
2.中缀队列转为后缀
QQueue<QString> QCalculatorDec::Transfer(QQueue<QString>& exp) //将中缀队列转换为后缀队列
{
QStack<QString> stack;
QQueue<QString> ret;
bool num_ok;
QString symbol;
while(!exp.isEmpty())
{
symbol = exp.dequeue(); //出队列
symbol.toDouble(&num_ok);
if(num_ok==true) //数字
{
stack.push(symbol);
}
else if(symbol=="+"||symbol=="-")
{
while(!stack.isEmpty() &&(stack.top()!="("))
{
ret.enqueue(stack.pop()); //取出栈顶运算符并入队列
}
stack.push(symbol);
}
else if(symbol=="*"||symbol=="/")
{
while(!stack.isEmpty() && (stack.top()!="(") && (stack.top()!="+") && (stack.top()!="-"))
{
ret.enqueue(stack.pop()); //取出栈顶运算符并入队列
}
stack.push(symbol);
}
else if(symbol == "(")
{
stack.push(symbol);
}
else if(symbol ==")")
{
while(!stack.isEmpty() && (stack.top()!="("))
{
ret.enqueue(stack.pop()); //取出栈顶运算符并入队列
}
if(stack.top()=="(")
stack.pop();
}
}
while(!stack.isEmpty()&& (stack.top()!="(")) //遍历完成,判断栈里是否为空
{
ret.enqueue(stack.pop()); //取出栈顶运算符并入队列
}return ret;
}
3.符号的运算规则
double left,right,res;
QString ret="";
left = l.toDouble();
right = r.toDouble();
if(op == "+")
{
res = left + right;
}
else if(op == "-")
{
res = left - right;
}
else if(op == "*")
{
res = left * right;
}
else if(op == "/")
{
if( (right>(-0.000000000000001)) && (right<(0.000000000000001)) ) //判断除数为0
return NULL;
else
res = left/right;
}
ret.sprintf("%f",res);
return ret;
4.计算后缀队列
QString QCalculatorDec::Calculate(QQueue<QString>& exp) //将后缀队列计算出结果
{
QStack<QString> stack;
QString symbol,L,R,op,ret;
bool num_ok;
while(!exp.isEmpty())
{
symbol = exp.dequeue(); //出队列
symbol.toDouble(&num_ok);
if(num_ok==true) //数字
{
stack.push(symbol);
}
else //运算符
{
if(stack.size()<2)
return "Error";
R= stack.pop();
L= stack.pop();
ret = Calculate(L,symbol,R );
if(ret==NULL)
return ret;
stack.push(ret);
}
}
if(stack.size()==1) //遍历完成,结果只有一个
{
return ValidNum(stack.pop());
}
else
{return "Error";
}
}
计算器界面的设计
1.按键生成与排版
const char* butnText[20]=
{
"C","<-",
"7","8","9","+","(",
"4","5","6","-",")",
"1","2","3","*","=",
"0", ".","/",
};
const int butnPos[20][4]= //存放 x y w h
{
{10,50,90,40},{110,50,140,40}, //<- C
{10,100,40,40},{60,100,40,40},{110,100,40,40},{160,100,40,40},{210,100,40,40}, //7 8 9 + (
{10,150,40,40},{60,150,40,40},{110,150,40,40},{160,150,40,40},{210,150,40,40}, //4 5 6 - )
{10,200,40,40},{60,200,40,40},{110,200,40,40},{160,200,40,40},{210,200,40,90}, //1 2 3 * =
{10,250,90,40}, {110,250,40,40},{160,250,40,40}, //0 . /
};
mline =new QLineEdit(this);
if(mline==NULL)
return false;
mline->resize(240,30);
mline->move(10,10);
mline->setAlignment(Qt::AlignRight);
mline->setReadOnly(1);
// mline->setFont(QFont(0,10)); //设置字体
this->setWindowTitle("计算器");
for(int i=0;i<20;i++)
{
mbuton[i]= new QPushButton(butnText[i],this);
if(mbuton[i]==NULL)
return false;
mbuton[i]->resize(butnPos[i][2],butnPos[i][3]);
mbuton[i]->move(butnPos[i][0],butnPos[i][1]);
QObject::connect(mbuton[i],SIGNAL(clicked()),this,SLOT(handler_clicked()));
}
return true;
2.一些限制条件及按键的处理
static int ClearLine=0;
static int bracket_cnt=0; //圆括号计数
QPushButton *btn =dynamic_cast<QPushButton* >(sender()); //获取对象
QString line = mline->text();
QString text = btn->text(); //获取消息
if(ClearLine)
{
mline->setText("");
line.clear();
ClearLine=0;
}if(text>="0"&&text<="9") //数字
{
QString tmp= line.right(1);
if(tmp.length() && tmp[0]==')') //数字前面不能为右括号
{
return;
}
line+=text;
}
else if(text=="." ) //小数点
{
QString tmp= line.right(1);
if(tmp.length()) //小数点前面只能是数字
{
if(MatchingBoth(tmp,"0123456789")== -1) //没找到数字
{
return;
}
}
else //小数点前面为空
{
return ;
}
int pos= LastMatchingBoth(line,"+-*/.()"); //反向查找
if(pos!= -1 &&line[pos]=='.' ) //一串数字只能有一个小数点
{
return ;
}
line+=text;
}
else if(text=="+"||text=="-") //加减号
{
QString tmp= line.right(1);
if(tmp.length()&& tmp[0]=='.') //前面不能为:小数点
{
return ;
}
tmp= line.right(2);
if(tmp.length()==2) //前面不能连续有两次加减乘除
{
if(tmp[0]=='+'||tmp[0]=='-'||tmp[0]=='*'||tmp[0]=='/'||tmp[0]=='(')
if(tmp[1]=='+'||tmp[1]=='-'||tmp[1]=='*'||tmp[1]=='/')
return ;
}
line+=text;
}
else if(text=="*"||text=="/") //乘除号
{
QString tmp= line.right(1);
if(tmp.length()) //前面不能为:左括号,小数点,加减乘除,
{
if(MatchingBoth(tmp,"(.+-*/")!= -1) //查找左括号,小数点,加减乘除
{
return;
}
}
else //乘除号前面不能为空
return;
line+=text;
}
else if(text=="(") //左括号
{
QString tmp= line.right(1);
if(tmp.length()) //前面不能为:右括号,数字,小数点
{
if(MatchingBoth(tmp,")0123456789.")!= -1) //查找右括号,数字,小数点
{
return;
}
}
tmp= line.right(2);
if(tmp.length()==2) //前面不能连续有两次加减乘除
{
if(tmp[0]=='+'||tmp[0]=='-'||tmp[0]=='*'||tmp[0]=='/')
if(tmp[1]=='+'||tmp[1]=='-'||tmp[1]=='*'||tmp[1]=='/')
return ;
}
line+=text;
bracket_cnt++;
}
else if(text==")") //右括号
{
QString tmp= line.right(1);
if(bracket_cnt==0) //前面没有左括号
return;
if(tmp.length()) //前面不能为:加减乘除,小数点,左括号
{
if(MatchingBoth(tmp,"+-*/.(")!= -1) //查找加减乘除,小数点,左括号
{
return;
}
}
else //右括号前面不能为空
return;
line+=text;
bracket_cnt--;
}
else if(text=="<-") //<-
{
if(line.length())
line.chop(1);
}
else if(text=="C") //清空
{
line.clear();
bracket_cnt=0;
}
else if(text=="="&& line.length())
{
QString ret=mDec.Result(line);
if(ret==NULL) //除数为0
{
line += " : ";
line +="除数不能为0";
}
else if(ret=="Error")
{
line += ":";
line +="格式出错";
}
else
{
line += "=";
line += ret;
}
ClearLine =1;
}
mline->setText(line);
头文件里的一些声明
private:
QQueue<QString> Split(const QString& exp); //分离前缀
QQueue<QString> Transfer(QQueue<QString>& exp); //将中缀队列转换为后缀队列
QString Calculate(QQueue<QString>& exp); //将后缀队列计算出结果
QString Calculate(QString& l,QString& op,QString& r );
QString ValidNum(QString str);
public:
QCalculatorDec();
QString Result(const QString& exp);
private:
QCalculatorDec mDec;
QLineEdit *mline; //显示行
QPushButton *mbuton[20]; //按钮成员
QCalculatorUI();
bool construct();
QString result;//保存结果
QString hold;//保存记录
QString solution();//求解
QString poly;//保存多项式
private slots:
void handler_clicked(); //处理按键消息
private:
Ui::QCalculatorUI *ui;
public:
int MatchingBoth(QString &str1,const char *str2); //匹配str1和str2,判断str1是否有str2的字符
int LastMatchingBoth(QString &str1,const char *str2); //反向匹配str1和str2
static QCalculatorUI* NewIntance(); //成员需要资源申请,所以使用二阶构造
void show();
最终界面