前言
运用数据队列中的栈知识,使用Qt制作简易的计算器
功能概述
①支持中缀表达式的基本四则运算
②支持软(软件自带键盘),硬(实体键盘)键盘均可操作,并且按键时触发小特效
③支持查看历史记录
核心思路
将用户输入的表达式分解为运算符和操作数两类
运算符:"+", "-", "*", "/", "(", ")"
操作数: 即0~9和小数点的组合
然后设置两个栈:运算符栈optr和操作数栈opnd
首先置操作数栈opnd为空,再先将一个操作符"="压入运算符栈optr中作为栈底元素,然后从左到右遍历用户输入的表达式,表达式是一个字符串,记作infix,只要没有遍历到运算符,那么这一串数字整体就是一个操作数,将其压入opnd栈中,若遍历到运算符,则按下列规则计算:
①若infix[i]的优先级高于optr栈顶的运算符,则将infix[i]压入optr栈中
②若infix[i]的优先级低于optr栈顶的运算符,则弹出optr栈顶的运算符,并从opnd弹出两个操作数,进行相应算术运算后,结果再压入opnd栈中
③若infix[i]是"(",则压入optr栈中
④若infix[i]是")",并且optr栈顶是“(”,则optr退栈,从而消去了左右括号,根据规则②计算
⑤若infix[i]是"=","="优先级最低,则optr退栈,用弹出的运算符与从opnd栈中弹出的两个操作数进行运算,结果压入opnd栈中,这个过程一致持续到optr栈只剩下"="为止,运算结束
运算符之间的优先级关系
运算符 | = | ( | *和/ | +和- | ) |
栈内优先级 | 0 | 1 | 5 | 3 | 6 |
栈外优先级 | 0 | 6 | 4 | 2 | 1 |
功能演示
源代码
#include <QWidget>
#include<QStack>
#include<QDebug>
#include<QKeyEvent>
#include<QPushButton>
#include<QThread>
#include<QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
double jointNum(QString str,int &i);//提取操作数
int in_priority(char ch);//栈内运算符优先级
int out_priority(char ch);//栈外运算符优先级
int compare_priority(int in,int out); //比较栈内外的优先级
int calcualate_num(double num1,double num2,char oper);//根据运算符计算两个操作数
void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event);
void btn_highlight(QPushButton* btn); //键盘按下高亮
void btn_release(QPushButton* btn);//键盘释放
void de_weight(QVector<QString> &vec);//去重
private slots:
void on_btn_equal_clicked();
void on_btn_clear_clicked();
void on_btn_back_clicked();
void on_btn_1_clicked();
void on_btn_0_clicked();
void on_btn_point_clicked();
void on_btn_add_clicked();
void on_btn_sub_clicked();
void on_btn_3_clicked();
void on_btn_2_clicked();
void on_btn_multiply_clicked();
void on_btn_6_clicked();
void on_btn_5_clicked();
void on_btn_4_clicked();
void on_btn_divide_clicked();
void on_btn_9_clicked();
void on_btn_8_clicked();
void on_btn_7_clicked();
void on_btn_right_clicked();
void on_btn_left_clicked();
private:
Ui::Widget *ui;
QStack<char> optr;//运算符栈
QStack<double> opnd;//操作数栈
QString infix;//中缀表达式
QVector<QString> history_infix;//存储历史记录
};
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("计算器");
}
Widget::~Widget()
{
delete ui;
}
double Widget::jointNum(QString str, int &i)//分割,提取操作数
{
QString temp;
ui->le_show->clear();
double result;
//138×16-5
while(str[i]>='0'&&str[i]<='9') //处理小数点之前的部分
{
temp += str[i++];
}
if(str[i]=='.')//处理小数点之后的部分
{
i++;
temp+='.';
while(str[i]>='0'&&str[i]<='9') //处理小数点之前的部分
temp += str[i++];
}
result = temp.toDouble();
return result;
}
int Widget::in_priority(char ch)
{
int in;
switch(ch)
{
case '=':in = 0;break;
case '+':in = 3;break;
case '-':in = 3;break;
case '*':in = 5;break;
case '/':in = 5;break;
case '(':in = 1;break;
case ')':in = 6;break;
}
return in;
}
int Widget::out_priority(char ch)
{
int out;
switch(ch)
{
case '=':out = 0;break;
case '+':out = 2;break;
case '-':out = 2;break;
case '*':out = 4;break;
case '/':out = 4;break;
case '(':out = 6;break;
case ')':out = 1;break;
}
return out;
}
int Widget::compare_priority(int in, int out)
{
if(in<out)
return -1;
else if(in==out)
return 0;
else
return 1;
}
int Widget::calcualate_num(double num1, double num2, char oper)
{
switch(oper)
{
case '+':return num2+num1;
case '-':return num2-num1;
case '*':return num2*num1;
case '/':
{
if(num1 == 0)
{
QMessageBox::warning(this,"错误","除数为0!!!");
return 0;
}
return num2/num1;
}
}
}
void Widget::keyPressEvent(QKeyEvent *event) //键盘事件
{
infix = ui->le_show->text();
switch (event->key()) {
case 0x30:infix+="0";btn_highlight(ui->btn_0);break;
case 0x31:infix+="1";btn_highlight(ui->btn_1);break;
case 0x32:infix+="2";btn_highlight(ui->btn_2);break;
case 0x33:infix+="3";btn_highlight(ui->btn_3);break;
case 0x34:infix+="4";btn_highlight(ui->btn_4);break;
case 0x35:infix+="5";btn_highlight(ui->btn_5);break;
case 0x36:infix+="6";btn_highlight(ui->btn_6);break;
case 0x37:infix+="7";btn_highlight(ui->btn_7);break;
case 0x38:infix+="8";btn_highlight(ui->btn_8);break;
case 0x39:infix+="9";btn_highlight(ui->btn_9);break;
case 0x2b:infix+="+";btn_highlight(ui->btn_add);break;
case 0x2d:infix+="-";btn_highlight(ui->btn_sub);break;
case 0x2a:infix+="*";btn_highlight(ui->btn_multiply);break;
case 0x2f:infix+="/";btn_highlight(ui->btn_divide);break;
case 0x28:infix+="(";btn_highlight(ui->btn_left);break;
case 0x29:infix+=")"; btn_highlight(ui->btn_right);break;
case 0x2e:infix+="."; btn_highlight(ui->btn_point);break;
case 0x01000003:on_btn_back_clicked();btn_highlight(ui->btn_back);break; //退格
case 0x01000004:on_btn_equal_clicked();btn_highlight(ui->btn_equal);break; //等于
case 0x01000005:on_btn_equal_clicked();btn_highlight(ui->btn_equal);break; //等于
}
ui->le_show->setText(infix);
}
void Widget::keyReleaseEvent(QKeyEvent *event)
{
switch (event->key()) {
case 0x30:btn_release(ui->btn_0);break;
case 0x31:btn_release(ui->btn_1);break;
case 0x32:btn_release(ui->btn_2);break;
case 0x33:btn_release(ui->btn_3);break;
case 0x34:btn_release(ui->btn_4);break;
case 0x35:btn_release(ui->btn_5);break;
case 0x36:btn_release(ui->btn_6);break;
case 0x37:btn_release(ui->btn_7);break;
case 0x38:btn_release(ui->btn_8);break;
case 0x39:btn_release(ui->btn_9);break;
case 0x2b:btn_release(ui->btn_add);break;
case 0x2d:btn_release(ui->btn_sub);break;
case 0x2a:btn_release(ui->btn_multiply);break;
case 0x2f:btn_release(ui->btn_divide);break;
case 0x28:btn_release(ui->btn_left);break;
case 0x29: btn_release(ui->btn_right);break;
case 0x2e: btn_release(ui->btn_point);break;
case 0x01000003:btn_release(ui->btn_back);break; //退格
case 0x01000004:btn_release(ui->btn_equal);break; //等于
case 0x01000005:btn_release(ui->btn_equal);break; //等于
}
}
void Widget::btn_highlight(QPushButton *btn) //按下效果
{
btn->setStyleSheet("QPushButton{background-color: rgb(200, 200, 200);}");
}
void Widget::btn_release(QPushButton *btn) //释放效果
{
btn->setStyleSheet("QPushButton{background-color: rgb(240, 240, 240);}");
}
void Widget::de_weight(QVector<QString> &vec) //去重
{
for(int i = 0;i<vec.size();i++)
{
for(int j = i+1;j<vec.size();j++)
{
if(vec.at(j) == vec.at(i))
vec.removeAt(j);
}
}
}
void Widget::on_btn_equal_clicked()// =
{
ui->text_history->clear();
optr.clear();
opnd.clear();
infix = ui->le_show->text(); //获取表达式
if(infix[0]=="-")
infix = "0" + infix;
if(infix.isEmpty())
return;
optr.push('='); //=置于栈底,级别最低
int i = 0;
double num,a,b;
char item,ch;
while(!optr.empty())
{
if(infix[i]=="0"||infix[i]=="1"||infix[i]=="2"||infix[i]=="3"||infix[i]=="4"||infix[i]=="5"||
infix[i]=="6"||infix[i]=="7"||infix[i]=="8"||infix[i]=="9"||infix[i]==".") //数字字符或者.,则拼接并入栈
{
num = jointNum(infix,i);
opnd.push(num); //数字入栈
}
else //操作符
{ //12+13
item = optr.top();
switch(compare_priority(in_priority(item),out_priority(infix[i].toLatin1())))//比较运算符优先级,toLatin1:QChar->char
{
case -1:
{
optr.push(infix[i].toLatin1());//infix[i]优先级高,入栈
i++; //指向下一个字符
}
break;
case 0:
{
item = optr.pop(); //删除括号或者=
if(item!='=')
i++; //指向下一个字符
}
break;
case 1:
{
ch = optr.pop(); //infix[i]级别低,弹出一个运算符并弹出两个操作数进行运算后再压栈
a = opnd.pop();
b = opnd.pop();
opnd.push(calcualate_num(a,b,ch)); //运算后结果入栈
}
}
}
}
num = opnd.pop();
if(!opnd.empty())
qDebug()<<"error";
QString temp = infix + "="+ QString::number(num);
history_infix.push_back(temp);
de_weight(history_infix);//去重
for(int i = 0;i<history_infix.size();i++)
{
ui->text_history->append(history_infix.at(i));
}
ui->le_show->setText(QString::number(num));
infix = QString::number(num);
}
void Widget::on_btn_clear_clicked() //清空
{
ui->le_show->clear();
infix.clear();
}
void Widget::on_btn_back_clicked() //退格
{
infix.remove(infix.length()-1,1);
ui->le_show->setText(infix);
}
void Widget::on_btn_1_clicked()
{
infix += "1";
ui->le_show->setText(infix);
}
void Widget::on_btn_0_clicked()
{
infix += "0";
ui->le_show->setText(infix);
}
void Widget::on_btn_point_clicked()
{
infix += ".";
ui->le_show->setText(infix);
}
void Widget::on_btn_add_clicked()
{
infix += "+";
ui->le_show->setText(infix);
}
void Widget::on_btn_sub_clicked()
{
infix += "-";
ui->le_show->setText(infix);
}
void Widget::on_btn_3_clicked()
{
infix += "3";
ui->le_show->setText(infix);
}
void Widget::on_btn_2_clicked()
{
infix += "2";
ui->le_show->setText(infix);
}
void Widget::on_btn_multiply_clicked()
{
infix += "*";
ui->le_show->setText(infix);
}
void Widget::on_btn_6_clicked()
{
infix += "6";
ui->le_show->setText(infix);
}
void Widget::on_btn_5_clicked()
{
infix += "5";
ui->le_show->setText(infix);
}
void Widget::on_btn_4_clicked()
{
infix += "4";
ui->le_show->setText(infix);
}
void Widget::on_btn_divide_clicked()
{
infix += "/";
ui->le_show->setText(infix);
}
void Widget::on_btn_9_clicked()
{
infix += "9";
ui->le_show->setText(infix);
}
void Widget::on_btn_8_clicked()
{
infix += "8";
ui->le_show->setText(infix);
}
void Widget::on_btn_7_clicked()
{
infix += "7";
ui->le_show->setText(infix);
}
void Widget::on_btn_right_clicked()
{
infix += ")";
ui->le_show->setText(infix);
}
void Widget::on_btn_left_clicked()
{
infix += "(";
ui->le_show->setText(infix);
}
项目源码:https://github.com/17359830697/calcualate
这篇文章对你有帮助的话就点个赞吧~文章来源:https://www.toymoban.com/news/detail-476082.html
点赞收藏关注就是对我最大的支持~文章来源地址https://www.toymoban.com/news/detail-476082.html
到了这里,关于Qt制作计算器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!