基于QT5的计算器简单实现
程序员文章站
2024-01-14 11:27:04
...
本人实验室培训作业
需求:实现必要的计算器功能,合理化布局
UI布局:
逻辑思维:由于组件中的text()值多为QSTring类型,
1.将槽的操作都写成,往一个大字符串追加信息
2.将字符串解析,利用栈实现数据的先后弹出,操作符的优先顺序
具体实现代码如下:
由于代码中注释足够详细,不再做文字说明:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
QString numInfo;
void caculate();
int is_First(char a, char b);
struct node{
int flag;
union{
double a;
char op;
}num;
//public slots:
//空写slots,编译时会出错,导致无法编译,
//下次务必不要踩雷
};
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
//9月29号9:12
//10月3号0:13
//完成基本功能,运算逻辑均正确
//至于科学计算器其它复杂的功能,可日后添加
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QPixmap"
#include "QPushButton"
#include "QIcon"
#include "QPixmap"
#include "QSize"
#include "QDebug"
#include "QFont"
#include "QVector"
#include "QStack"
#include "math.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置固定尺寸
this->setFixedSize(1061,800);
this->setWindowIcon(QPixmap(":/res/caculater_icon.jpg"));
this->setWindowTitle("爷的科学计算器");
//计算符号图标
//Qicon会自动缩小,这里用Qpixmap先放大
ui->ride_btn->setIconSize(QSize(100,100));
ui->ride_btn->setIcon(QIcon(QPixmap(":/res/ride.png")));
ui->plus_btn->setIconSize(QSize(100,100));
ui->plus_btn->setIcon(QIcon(QPixmap(":/res/plus.png")));
ui->reduce_btn->setIconSize(QSize(100,100));
ui->reduce_btn->setIcon(QIcon(QPixmap(":/res/reduce.png")));
ui->equal_btn->setIconSize(QSize(100,100));
ui->equal_btn->setIcon(QIcon(QPixmap(":/res/equal.png")));
ui->clear_btn->setIconSize(QSize(100,100));
ui->clear_btn->setIcon(QIcon(QPixmap(":/res/clear.png")));
ui->back_btn->setIconSize(QSize(100,100));
ui->back_btn->setIcon(QIcon(QPixmap(":/res/back.png")));
ui->division_btn->setIconSize(QSize(100,100));
ui->division_btn->setIcon(QIcon(QPixmap(":/res/division.png")));
ui->left_btn->setIconSize(QSize(100,100));
ui->left_btn->setIcon(QIcon(QPixmap(":/res/left.png")));
ui->right_btn->setIconSize(QSize(100,100));
ui->right_btn->setIcon(QIcon(QPixmap(":/res/right.png")));
ui->mod_btn->setIconSize(QSize(100,100));
ui->mod_btn->setIcon(QIcon(QPixmap(":/res/mod.png")));
if(this->ui->history_label->text() == ""){
this->ui->history_label->setText("尚无历史记录");
}
//上面发现label字体太小
QFont font;
font.setPointSize(20);
ui->screen_label->setFont(font);
//通过按钮的text获得按钮代表数字
this->numInfo = "";
//写好获取text值,追加字符串之后
//将btn的clicked与this.slots{}连接
//不写槽了,用lamda表达式直接模式粘贴复制
//可以提模板,但是已经写完了
connect(ui->num1_btn,&QPushButton::clicked,[=](){
this->numInfo += this->ui->num1_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
});
connect(ui->num2_btn,&QPushButton::clicked,[=](){
this->numInfo += this->ui->num2_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
});
connect(ui->num3_btn,&QPushButton::clicked,[=](){
this->numInfo += this->ui->num3_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
});
connect(ui->num4_btn,&QPushButton::clicked,[=](){
this->numInfo += this->ui->num4_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
});
connect(ui->num5_btn,&QPushButton::clicked,[=](){
this->numInfo += this->ui->num5_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
});
connect(ui->num6_btn,&QPushButton::clicked,[=](){
this->numInfo += this->ui->num6_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
});
connect(ui->num7_btn,&QPushButton::clicked,[=](){
this->numInfo += this->ui->num7_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
});
connect(ui->num8_btn,&QPushButton::clicked,[=](){
this->numInfo += this->ui->num8_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
});
connect(ui->num9_btn,&QPushButton::clicked,[=](){
this->numInfo += this->ui->num9_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
});
connect(ui->num0_btn,&QPushButton::clicked,[=](){
this->numInfo += this->ui->num0_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
});
connect(ui->point_btn,&QPushButton::clicked,[=](){
if(this->numInfo != " "){
this->numInfo += this->ui->point_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
}
});
connect(ui->equal_btn ,&QPushButton::clicked,[=](){
if(this->numInfo != " "){
this->caculate();
this->ui->history_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
}
});
connect(ui->left_btn,&QPushButton::clicked,[=](){
if(this->numInfo != " "){
this->numInfo += this->ui->left_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
}
});
connect(ui->right_btn,&QPushButton::clicked,[=](){
if(this->numInfo != " "){
this->numInfo += this->ui->right_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
}
});
connect(ui->plus_btn,&QPushButton::clicked,[=](){
if(this->numInfo != " "){
this->numInfo += this->ui->plus_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
}
});
connect(ui->ride_btn,&QPushButton::clicked,[=](){
if(this->numInfo != " "){
this->numInfo += this->ui->ride_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
}
});
connect(ui->reduce_btn,&QPushButton::clicked,[=](){
if(this->numInfo != " "){
this->numInfo += this->ui->reduce_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
}
});
connect(ui->division_btn,&QPushButton::clicked,[=](){
if(this->numInfo != " "){
this->numInfo += this->ui->division_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
}
});
connect(ui->clear_btn,&QPushButton::clicked,[=](){
this->numInfo = "";
this->ui->screen_label->setText(this->numInfo);
});
connect(ui->back_btn,&QPushButton::clicked,[=](){
this->numInfo = this->numInfo.left(this->numInfo.size()-1);
ui->screen_label->setText(this->numInfo);
});
connect(ui->mod_btn,&QPushButton::clicked,[=](){
if(this->numInfo != " "){
this->numInfo += this->ui->mod_btn->text();
this->ui->screen_label->setText(this->numInfo);
qDebug() << this->numInfo <<endl;
}
});
}
//字符串算式解析的方法实现
void MainWindow::caculate(){
// QVector<double> numlist;
node nodeList[20];
double num = 0;
//设置位置
int position = 0;
//设置浮点数标志
int float_flog = 0;
//浮点数的小数数量,整数数量
int num_of_float = 0;
int num_of_int = 0;
//获取字符串长度
int len = this->numInfo.size();
//老子不用vector了
// double numlist[len];
//提取整数
while(position < len){
if(numInfo[position] >= '0' && numInfo[position] <= '9'){
if(!float_flog){
//将字符串的元素转化为ASCII码
/*返回相当于QChar的拉丁语-1字符,或0。这主要用于非国际化软件。
注意:不可能区分非拉丁1字符和拉丁10(NUL)字符。更喜欢使用unicode(),它没有这种模糊性。
百度结果*/
num = num*10 + (numInfo[position].toLatin1()-'0');
++position;
}
else{
//这一块是算小数部分
double p = 1;
for(int k = 0; k < num_of_float;k++){
p *= 0.1;
}
num += (numInfo[position].toLatin1()-'0')*p;
num_of_float++;
++position;
}
}
//这块是读到小数点,设置标志,设置小数数量(含小数点)
else if (numInfo[position] == '.') {
float_flog = 1;
num_of_float = 1;
++position;
}
//下面是读到运算符的情况
else {
if(num){
nodeList[num_of_int].flag = 0;
nodeList[num_of_int].num.a = num;
qDebug() <<nodeList[num_of_int].num.a;
num = 0;
++num_of_int;
float_flog = 0;
num_of_float = 0;
//莫名其妙的bug
// qDebug() << QString("%1").arg((numlist.at(1)+numlist.at(2)));
// this->numInfo += QString("%1").arg((numlist.at(1)+numlist.at(2)));
// while(i>=1){
// qDebug() << QString("%1").arg((numlist[i]+numlist[i-1]));
// break;
// }
}
nodeList[num_of_int].flag = 1;
nodeList[num_of_int].num.op = numInfo[position].toLatin1();
++num_of_int;
++position;
}
}
//最后一个操作数
if(num){
nodeList[num_of_int].flag = 0;
nodeList[num_of_int].num.a = num;
qDebug() <<nodeList[num_of_int].num.a;
++num_of_int;
num = 0;
}
//利用栈的存储特性,将符号存入并按后缀的顺序读出
//创建一个Qstack类型的,保存操作符的栈
QStack<node> signList;
//临时性出栈操作符
node temporarySign_node[20];
int j = 0;
for(int m = 0; m < num_of_int;){
if(nodeList[m].flag){
if(signList.isEmpty()){
signList.push(nodeList[m++]);
}
else{
node temp = signList.top();
//判断运算符优先级
int res = is_First(temp.num.op,nodeList[m].num.op);
switch (res) {
case -1:
signList.push(nodeList[m++]);
break;
case 1:
temporarySign_node[j++] = signList.top();
signList.pop();
break;
default:
signList.pop();
m++;
break;
}
}
}
else {
temporarySign_node[j++] = nodeList[m++];
}
}
//处理算式中的括号
while(!signList.isEmpty()){
node tem = signList.top();
if(tem.num.op != '(' &&tem.num.op != ')'){
temporarySign_node[j++] = tem;
}
signList.pop();
}
QStack<double> last_signList;
double d1 = 0,d2 = 0;
for(int n = 0; n < j ; n++){
//遇到符号弹出数字,弹出前两个数字
if(temporarySign_node[n].flag){
d2 = last_signList.top();
last_signList.pop();
d1 = last_signList.top();
last_signList.pop();
switch(temporarySign_node[n].num.op)
{
case '+':
d1 += d2;
break;
case '-':
d1 -= d2;
break;
case '*':
d1 *= d2;
break;
case '/':
d1 /= d2;
break;
case '%':
//注意,这块是浮点数去模,一定要注意用fmod方法,头文件为math.h
//切记不要再次踩雷
d1 = fmod(d1,d2);
break;
default:
break;
}
last_signList.push(d1);
}
else
{
last_signList.push(temporarySign_node[n].num.a);
}
}
qDebug() << d1;
this->numInfo += '=';
this->numInfo += QString::number(d1);
this->ui->screen_label->setText(this->numInfo);
}
//返回整形标志的运算符优先级比对结果
int MainWindow::is_First(char a, char b){
char aim[7][8] = {{ ">><<<>>" },{ ">><<<>>" },{ ">>>><>>" },{ ">>>><>>" },{ "<<<<<=1" },{ ">>>>1>>" },{ "<<<<<1=" }};
char sta[7] = { '+','-','*','/','(',')','#' };
char result;
int i,pa,pb;
for (i = 0; i<6; i++)
{
if (a == sta[i])
{
pa = i;
}
if (b == sta[i])
{
pb = i;
}
}
result = aim[pa][pb];
if(result == '>')return 1;
else if(result == '<')return -1;
else return 0;
}
MainWindow::~MainWindow()
{
delete ui;
}
不可描述的雷:
第一遍运行时,系统会一直报构建方法出错,还不告诉你第几行出错,经查询,把build_debug的文件夹删了就可通顺运行,原因是第一遍程序已经qmake,后面在debug后,再次qmake,build_debug文件夹中的debug文件会与程序重现qmake的步骤相冲突
运行结果图:
最大的点:
可以用toDoule方法直接解析字符串算式,不用上面那种繁琐的方法,但是!!!
我已经写完了,淦
上一篇: Matplotlib绘图和可视化