初学Qt,制作一个简单计算器。
先上效果图:
上面显示框,用于显示输入:
如:1*2-(3-8)+2*6
按下等于键,下面显示框显示输出结果:
1,计算器界面设计
因为本人初学,就直接在ui界面画出所需界面了,如下:
在界面画好之后,记得要布局,让其界面一直处于居中状态,另外可以右键,选择修改每个控件名字,便于对各个控件编程。
2,总体设计思路。
由界面设计。我们可以看出,有两个显示框,当我们输入表达式时,要实时显示到界面上,那我们可以将上面的框用于显示输入表达式,下面的框用于显示输入的数据及最后的运算结果。
我们定义一个结构体:
struct put_ctrl_t{
QString old_put; //用于表达式的存储
QString new_put; //用于输入的数据存储
int brackets_cnt; //左括号输入个数
int update_flag; //当new_put为“0”时,重新输入0表示更新置1
};
计算器是模仿win10的自带的标准计算器,显示方式和其相似。
当我们输入1+2=时,
(1)—>input 1
old_put = “0”;//初始值
new_put = “1”;
(2)—->input +
old_put = “1+”;//显示到上框
new_put = “0”;//初始化
(3)—->input 2
old_put = “1+”;//显示到上框
new_put = “2”;
(4)—->input =
old_put = “1+2”;//不显示,计算结果显示到下框,上框清空
new_put = “0”;
old_put = “0”;//初始化
3,计算器按键输入信号绑定connect。
/*所有按键,信号连接*/
connect(ui>button_0,SIGNAL(clicked()),this,SLOT(push_button_0()));
connect(ui->button_1,SIGNAL(clicked()),this,SLOT(push_button_1()));
connect(ui->button_2,SIGNAL(clicked()),this,SLOT(push_button_2()));
connect(ui->button_3,SIGNAL(clicked()),this,SLOT(push_button_3()));
connect(ui->button_4,SIGNAL(clicked()),this,SLOT(push_button_4()));
connect(ui->button_5,SIGNAL(clicked()),this,SLOT(push_button_5()));
connect(ui->button_6,SIGNAL(clicked()),this,SLOT(push_button_6()));
connect(ui->button_7,SIGNAL(clicked()),this,SLOT(push_button_7()));
connect(ui->button_8,SIGNAL(clicked()),this,SLOT(push_button_8()));
connect(ui->button_9,SIGNAL(clicked()),this,SLOT(push_button_9()));
connect(ui->button_point,SIGNAL(clicked()),this,SLOT(push_button_point()));
connect(ui->button_left,SIGNAL(clicked()),this,SLOT(push_button_left()));
connect(ui->button_right,SIGNAL(clicked()),this,SLOT(push_button_right()));
connect(ui->button_add,SIGNAL(clicked()),this,SLOT(push_button_add()));
connect(ui->button_minus,SIGNAL(clicked()),this,SLOT(push_button_minus()));
connect(ui->button_ride,SIGNAL(clicked()),this,SLOT(push_button_ride()));
connect(ui->button_divide,SIGNAL(clicked()),this,SLOT(push_button_divide()));
connect(ui->button_equal,SIGNAL(clicked()),this,SLOT(push_button_equal()));
connect(ui->button_AC,SIGNAL(clicked()),this,SLOT(push_button_AC()));
connect(ui>button_CE,SIGNAL(clicked()),this,SLOT(push_button_CE()));
4,按键输入处理函数。主要注意的就是(),+,-,*,/,小数点的输入,数字输入主要注意0的输入即可,下方是详细代码。仔细看一下应该就可以懂得,没有很多复杂的操作,都是字符串和逻辑的操作。
/*数据按键输入*/
void Calculator::push_button_0()
{
if(put_ctrl.new_put == "0"){
put_ctrl.new_put = "0";
put_ctrl.update_flag = 1;
}
else
put_ctrl.new_put += "0";
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_1()
{
if(put_ctrl.new_put == "0")
put_ctrl.new_put = "1";
else
put_ctrl.new_put += "1";
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_2()
{
if(put_ctrl.new_put == "0")
put_ctrl.new_put = "2";
else
put_ctrl.new_put += "2";
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_3()
{
if(put_ctrl.new_put == "0")
put_ctrl.new_put = "3";
else
put_ctrl.new_put += "3";
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_4()
{
if(put_ctrl.new_put == "0")
put_ctrl.new_put = "4";
else
put_ctrl.new_put += "4";
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_5()
{
if(put_ctrl.new_put == "0")
put_ctrl.new_put = "5";
else
put_ctrl.new_put += "5";
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_6()
{
if(put_ctrl.new_put == "0")
put_ctrl.new_put = "6";
else
put_ctrl.new_put += "6";
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_7()
{
if(put_ctrl.new_put == "0")
put_ctrl.new_put = "7";
else
put_ctrl.new_put += "7";
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_8()
{
if(put_ctrl.new_put == "0")
put_ctrl.new_put = "8";
else
put_ctrl.new_put += "8";
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_9()
{
if(put_ctrl.new_put == "0")
put_ctrl.new_put = "9";
else
put_ctrl.new_put += "9";
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_point()
{
if(put_ctrl.new_put == "0")
put_ctrl.new_put = "0.";
else{
if(-1 == put_ctrl.new_put.indexOf("."))
put_ctrl.new_put += ".";
}
ui->put_data->setText(put_ctrl.new_put);
}
void Calculator::push_button_left()
{
if(put_ctrl.old_put == "0"){
put_ctrl.old_put = "(";
put_ctrl.brackets_cnt ++;
}
else{
put_ctrl.old_put += "(";
put_ctrl.brackets_cnt ++;
}
ui->display->setText(put_ctrl.old_put);
}
void Calculator::push_button_right()
{
if(put_ctrl.brackets_cnt > 0){
QString::iterator p = put_ctrl.old_put.end()-1;
if(*p != ')')
put_ctrl.old_put += put_ctrl.new_put;
put_ctrl.old_put += ")";
put_ctrl.brackets_cnt --;
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
ui->display->setText(put_ctrl.old_put);
}
}
/*+ - * / = 按键输入*/
void Calculator::push_button_add()
{
if(put_ctrl.old_put == "0"){
put_ctrl.old_put = put_ctrl.new_put;
put_ctrl.old_put += "+";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
else{
QString::iterator p = put_ctrl.old_put.end()-1;
if(*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '(' ){
if(put_ctrl.new_put == "0"){
if(put_ctrl.update_flag){
put_ctrl.old_put += put_ctrl.new_put;
put_ctrl.old_put += "+";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
}else{
put_ctrl.old_put += put_ctrl.new_put;
put_ctrl.old_put += "+";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
}else if(*p == ')') {
put_ctrl.old_put += "+";
}
}
ui->display->setText(put_ctrl.old_put);
}
void Calculator::push_button_minus()
{
if(put_ctrl.old_put == "0"){
put_ctrl.old_put = put_ctrl.new_put;
put_ctrl.old_put += "-";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
else{
QString::iterator p = put_ctrl.old_put.end()-1;
if(*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '(' ){
if(put_ctrl.new_put == "0"){
if(put_ctrl.update_flag || *p == '('){
put_ctrl.old_put += put_ctrl.new_put;
put_ctrl.old_put += "-";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
}else{
put_ctrl.old_put += put_ctrl.new_put;
put_ctrl.old_put += "-";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
}else if(*p == ')') {
put_ctrl.old_put += "-";
}
}
ui->display->setText(put_ctrl.old_put);
}
void Calculator::push_button_ride()
{
if(put_ctrl.old_put == "0"){
put_ctrl.old_put = put_ctrl.new_put;
put_ctrl.old_put += "*";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
else{
QString::iterator p = put_ctrl.old_put.end()-1;
if(*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '(' ){
if(put_ctrl.new_put == "0"){
if(put_ctrl.update_flag){
put_ctrl.old_put += put_ctrl.new_put;
put_ctrl.old_put += "*";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
}else{
put_ctrl.old_put += put_ctrl.new_put;
put_ctrl.old_put += "*";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
}else if(*p == ')') {
put_ctrl.old_put += "*";
}
}
ui->display->setText(put_ctrl.old_put);
}
void Calculator::push_button_divide()
{
if(put_ctrl.old_put == "0"){
put_ctrl.old_put = put_ctrl.new_put;
put_ctrl.old_put += "/";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
else{
QString::iterator p = put_ctrl.old_put.end()-1;
if(*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '(' ){
if(put_ctrl.new_put == "0"){
if(put_ctrl.update_flag){
put_ctrl.old_put += put_ctrl.new_put;
put_ctrl.old_put += "/";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
}else{
put_ctrl.old_put += put_ctrl.new_put;
put_ctrl.old_put += "/";
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
}else if(*p == ')') {
put_ctrl.old_put += "/";
}
}
ui->display->setText(put_ctrl.old_put);
}
void Calculator::push_button_equal()
{
if(put_ctrl.old_put == "0"){
push_button_AC();
return;
}
else{
QString::iterator p = put_ctrl.old_put.end()-1;
if(*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '(' ){
put_ctrl.old_put += put_ctrl.new_put;
if(put_ctrl.brackets_cnt > 0){
for(int i = 0 ; i < put_ctrl.brackets_cnt ; i++)
put_ctrl.old_put += ")";
}
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}else if(*p == ')') {
if(put_ctrl.brackets_cnt > 0){
for(int i = 0 ; i < put_ctrl.brackets_cnt ; i++)
put_ctrl.old_put += ")";
}
put_ctrl.new_put = "0";
put_ctrl.update_flag = 0;
}
}
calculate_result(put_ctrl.old_put);
put_ctrl.old_put = "0";
put_ctrl.brackets_cnt = 0;
put_ctrl.update_flag = 0;
put_ctrl.new_put = "0";
}
void Calculator::push_button_CE()
{
put_ctrl.old_put = "0";
ui->display->clear();
}
void Calculator::push_button_AC()
{
put_ctrl.old_put = "0";
put_ctrl.new_put = "0";
put_ctrl.brackets_cnt = 0;
put_ctrl.update_flag = 0;
ui->display->clear();
ui->put_data->setText(put_ctrl.new_put);
}
5,获得的表达式如何计算。这里贴下计算的源码,详细的下篇博客分析一下。
/*获取操作符优先级*/
int Calculator::Priority(QString data)
{
int priority;
if(data == "(")
priority = 1;
else if(data == "+" || data == "-")
priority = 2;
else if(data == "*" || data == "/")
priority = 3;
else if (data == ")")
priority = 4;
else
priority = -1;
return priority;
}
/*将表达式的数据,操作符分割,依次存入mask_buffer数组中*/
int Calculator::mask_data(QString expression, QString *mask_buffer)
{
int i,k = 0,cnt = 0;
QString::iterator p = expression.begin();
int length = expression.length();
for(i = 0 ; i < length ; i += cnt,k++)
{
cnt = 0;
if(*p >= '0' && *p <= '9')
{
QString temp = *p;
p ++;
cnt ++;
while((*p >= '0' && *p <= '9') || *p == '.')
{
temp += *p;
p++;
cnt ++;
}
mask_buffer[k] = temp;
}else{
QString temp = *p;
p++;
cnt ++;
mask_buffer[k] = temp;
}
}
return k;
}
/*将获取到的分割好的表达式数组,转化为逆波兰表达式,存入数组repolish中*/
int Calculator::re_polish(QString *mask_buffer,QString *repolish,int length)
{
QStack st2;
int i = 0;
for(int j = 0 ; j < length ; j++)
{
if(mask_buffer[j] != "(" && mask_buffer[j] != ")" && mask_buffer[j] != "+" && mask_buffer[j] != "-" && mask_buffer[j] != "*" && mask_buffer[j] != "/" )
repolish[i++] = mask_buffer[j];
else if(mask_buffer[j] == "("){
st2.push(mask_buffer[j]);
}
else if(mask_buffer[j] == ")"){
while(st2.top() != "(")
{
repolish[i++] = st2.top();
st2.pop();
}
if(st2.top() == "(")
st2.pop();
}
else if(st2.empty() || Priority(mask_buffer[j]) > Priority(st2.top()))
st2.push(mask_buffer[j]);
else{
while(Priority(mask_buffer[j]) <= Priority(st2.top()))
{
repolish[i++] = st2.top();
st2.pop();
if(st2.empty())
break;
}
st2.push(mask_buffer[j]);
}
}
while(!st2.empty())
{
repolish[i++] = st2.top();
st2.pop();
}
return i;
}
/*计算逆波兰表达式值并显示*/
double Calculator::repolish_calculat(QString *repolish,int length)
{
QStack <double> st;
for(int m = 0 ; m < length ; m ++)
{
if(repolish[m] != "+" && repolish[m] != "-" && repolish[m] != "*" && repolish[m] != "/" )
{
st.push(repolish[m].toDouble());
}
else
{
if(repolish[m] == "+")
{
double a = st.top();
st.pop();
double b = st.top();
st.pop();
st.push(b + a);
}
else if(repolish[m] == "-")
{
double a = st.top();
st.pop();
double b = st.top();
st.pop();
st.push(b - a);
}
else if(repolish[m] == "*")
{
double a = st.top();
st.pop();
double b = st.top();
st.pop();
st.push(b * a);
}
else if(repolish[m] == "/")
{
double a = st.top();
st.pop();
double b = st.top();
st.pop();
if(a != 0)
st.push(b/a);
else
{
ui->display->clear();
ui->put_data->setText("0 不能做除数");
return -1;
}
}
}
}
QString res = QString::number(st.top(),'g',10);
ui->display->clear();
ui->put_data->setText(res);
return st.top();
}
/*表达式计算整合*/
void Calculator::calculate_result(QString expression)
{
QString mask_buffer[100]={"0"},repolish[100]={"0"};
int length = mask_data(expression,mask_buffer);
length = re_polish(mask_buffer,repolish,length);
double result = repolish_calculat(repolish,length);
}
6,源码包。
为了方便,我这里将整个工程打包,大家如果需要的话可以下载。还有很多不足之处,希望一起交流,进步。
链接:http://pan.baidu.com/s/1i5R67zv 密码:dd9s