Qt制作简易计算器 3.15数据库课程作业

Qt是C++的一个开发图形用户界面的框架,支持windows、linux、Android等很多平台

这次的作业就是用Qt,模仿着win10系统自带的标准计算器制作的,并运用逆波兰算法实现了优先级加减乘除

1、运行流程

输入表达式后,检查表达式格式是否正确,正确则计算结果,否则提示Error

2、功能介绍

数字键和加、减、乘、除运算符不必说,可进行优先级加减乘除,且可计算小数。
%计算百分数,1/x表示倒数,^2平方,^0.5开平方根,+/-变相反数,C清屏,R退格


当表达式输入完毕,按下=进行计算时,会进行表达式格式检测
例如两个运算符相邻、一个数多个小数点、除0等均为不合法,会提示Error


其他的取百分数、平方、相反数等功能仅能对上次合法表达式所计算的结果进行计算,在输入表达式时使用会提示Error

3、GUI界面设计

Qt也提供了ui界面,可以像C#、Android Studio那样拖动控件进行布局,很直观的修改控件的属性,如名字、字体颜色等


布局使用了Qt的水平布局和垂直布局

5排按键,每一排进行水平布局后,整体进行垂直布局,再和文本框垂直布局,实现窗体内控件尺寸随窗体的变化而变化

我设置的文本框高度限度为120px,文本框高度固定,宽度随窗体变化而变化。控件位置是相对窗体的,不是固定的

4、代码实现


仅仅设计了一个类Calculator,利用Qt的信号和槽实现按钮点击效果,slot函数即点击按钮后执行的函数

rescource.qrc为资源文件,仅存储了程序图标一张图片

头文件如下:

#ifndef COMPUTER_H
#define COMPUTER_H

#include <QWidget>
#include <QPushButton>
#include <QDebug>
#include <cmath>
#include <string>
#include <stack>

using namespace std;

namespace Ui {
    class Computer;
}

class Calculator : public QWidget {
    Q_OBJECT

public:
    explicit Calculator(QWidget *parent = 0);
    ~Calculator();

private:
    Ui::Computer *ui;//ui界面指针
    QString calculate_;//当前表达式
    QString cal_ret = ""; //上一个表达式的计算结果
    QString error_qstr[4] = {"", "= Empty", "= Error N/0", "= Error"};//错误类型
    size_t check_calculate_(const QString &qstr) const;//检查表达式是否合法
    QString get_suffix(const QString &qstr) const;//计算表达式后缀表示形式
    QString get_result(const QString &qstr) const;//计算后缀式结果

private slots:
    void edit_append_num();//按数字
    void edit_append_oper();//按运算符
    void edit_append_oth();//按下其他 平方等
    void edit_append_ret();//计算结果
    void edit_change();//C和R
};

#endif // COMPUTER_H 防卫

Qt对stl几乎整体重构,大部分容器做了改变,QString代替string,我用string习惯了,所以很多时候转化为string后实现算法‘

实现文件如下,标注了注释:

#include "Calculator.h"
#include "ui_computer.h"

Calculator::Calculator(QWidget *parent)
    : QWidget(parent), ui(new Ui::Computer) {
    ui->setupUi(this);
    ui->edit_ret->setWordWrapMode(QTextOption::WrapAnywhere);
    connect(ui->bon_num_0, &QPushButton::clicked, this, &Calculator::edit_append_num);//数字0
    connect(ui->bon_num_1, &QPushButton::clicked, this, &Calculator::edit_append_num);//数字1
    connect(ui->bon_num_2, &QPushButton::clicked, this, &Calculator::edit_append_num);//数字2
    connect(ui->bon_num_3, &QPushButton::clicked, this, &Calculator::edit_append_num);//数字3
    connect(ui->bon_num_4, &QPushButton::clicked, this, &Calculator::edit_append_num);//数字4
    connect(ui->bon_num_5, &QPushButton::clicked, this, &Calculator::edit_append_num);//数字5
    connect(ui->bon_num_6, &QPushButton::clicked, this, &Calculator::edit_append_num);//数字6
    connect(ui->bon_num_7, &QPushButton::clicked, this, &Calculator::edit_append_num);//数字7
    connect(ui->bon_num_8, &QPushButton::clicked, this, &Calculator::edit_append_num);//数字8
    connect(ui->bon_num_9, &QPushButton::clicked, this, &Calculator::edit_append_num);//数字9
    connect(ui->bon_decimal, &QPushButton::clicked, this, &Calculator::edit_append_num);//小数点
    connect(ui->bon_add, &QPushButton::clicked, this, &Calculator::edit_append_oper);//加
    connect(ui->bon_del, &QPushButton::clicked, this, &Calculator::edit_append_oper);//减
    connect(ui->bon_pro, &QPushButton::clicked, this, &Calculator::edit_append_oper);//乘
    connect(ui->bon_fix, &QPushButton::clicked, this, &Calculator::edit_append_oper);//除
    connect(ui->bon_ret, &QPushButton::clicked, this, &Calculator::edit_append_ret);//计算结果
    connect(ui->bon_era, &QPushButton::clicked, this, &Calculator::edit_change);//删除全部
    connect(ui->bon_rem, &QPushButton::clicked, this, &Calculator::edit_change);//表达式退格
    connect(ui->bon_neg, &QPushButton::clicked, this, &Calculator::edit_append_oth); //相反数
    connect(ui->bon_sqr, &QPushButton::clicked, this, &Calculator::edit_append_oth); //开根号
    connect(ui->bon_squ, &QPushButton::clicked, this, &Calculator::edit_append_oth); //平方
    connect(ui->bon_con, &QPushButton::clicked, this, &Calculator::edit_append_oth); //倒数
    connect(ui->bon_bai, &QPushButton::clicked, this, &Calculator::edit_append_oth); //百分数
}

//按下数字
void Calculator::edit_append_num() {
    QPushButton *bon = qobject_cast<QPushButton *>(sender());
    calculate_ += bon->text();//更新表达式状态
    QString str = ui->edit_ret->toPlainText();
    ui->edit_ret->clear();
    ui->edit_ret->append(str + bon->text());
}

//按下+-*/运算符
void Calculator::edit_append_oper() {
    QPushButton *bon = qobject_cast<QPushButton *>(sender());
    QString qstr;
    if(bon == ui->bon_add) {
        qstr = "+";
    } else if(bon == ui->bon_del) {
        qstr = "-";
    } else if(bon == ui->bon_pro) {
        qstr = "*";
    } else if(bon == ui->bon_fix) {
        qstr = "/";
    } else {//程序出错
        exit(0);
    }
    calculate_ += " " + qstr + " ";//更新表达式状态
    QString str = ui->edit_ret->toPlainText();
    ui->edit_ret->clear();
    ui->edit_ret->append(str + bon->text());
}

//按下其他,平方等
void Calculator::edit_append_oth() {
    if(calculate_ > 0) { //有正在输入的表达式
        calculate_.clear();
        ui->edit_ret->append(error_qstr[3]);
    } else {
        if(cal_ret.size() <= 0) { //没有计算结果
            ui->edit_ret->append(error_qstr[1]);
        } else {
            QPushButton *bon = qobject_cast<QPushButton *>(sender());//获取信号发送对象
            double ret = cal_ret.toDouble();
            if(bon == ui->bon_neg) { //相反数
                ui->edit_ret->insertPlainText("negate(" + cal_ret + ")");
                ret = -ret;
            } else if(bon == ui->bon_sqr) { //平方
                ui->edit_ret->insertPlainText("sqrt(" + cal_ret + ")");
                ret = pow(ret, 2);
            } else if(bon == ui->bon_squ) { //开平方根
                ui->edit_ret->insertPlainText("√(" + cal_ret + ")");
                if(ret < 0) { //数小于0,不能开平方根
                    ui->edit_ret->append(error_qstr[3]);
                    ui->edit_ret->append("");
                    return;
                } else {
                    ret = pow(ret, 0.5);
                }
            } else if(bon == ui->bon_bai) { //百分数
                ui->edit_ret->insertPlainText("(" + cal_ret + ")*100%");
                ret = ret / 100;
            } else if(bon == ui->bon_con) { //倒数
                ui->edit_ret->insertPlainText("1/(" + cal_ret + ")");
                ret = ret == 0.0 ? 0 : 1 / ret;
            }
            cal_ret = QString::number(ret);
            ui->edit_ret->append("= " + cal_ret);
        }
    }
    ui->edit_ret->append("");
}

//按下=
void Calculator::edit_append_ret() {
    size_t flag = check_calculate_(calculate_);
    if(flag == 0) {//运算正常
        cal_ret = get_result(get_suffix(calculate_));
        ui->edit_ret->append("= " + cal_ret);
        calculate_.clear();
    } else {
        switch (flag) {
            case 1:
                ui->edit_ret->append("= Empty");//表达式为空
                break;
            case 2:
                ui->edit_ret->append("= Error N/0");//除0
                break;
            case 3:
                ui->edit_ret->append("= Error");//表达式错误
                break;
            default:
                ui->edit_ret->append("= N/A");//内存漏了
                break;
        }
    }
    ui->edit_ret->append("");//另起一行
}

//退格和清屏
void Calculator::edit_change() {
    QPushButton *bon = qobject_cast<QPushButton *>(sender());
    if(bon == ui->bon_era) { //全部删除
        ui->edit_ret->clear();
        calculate_.clear();
    } else {//删除表达式末尾
        if(calculate_.size() > 0) {//当前表达式不为空
            QTextCursor tc = ui->edit_ret->textCursor();//获取表达式末尾光标
            tc.deletePreviousChar();//删除该光标前一个字符
            if(calculate_[calculate_.size() - 1] == ' ') {//退格遇到运算符
                calculate_.chop(3);//删去最后3个
            } else {
                calculate_.chop(1);//删去最后1个
            }
        }
    }
}

//检查表达式是否合法
size_t Calculator::check_calculate_(const QString &qstr) const {
    string str = qstr.toStdString();//转为标准字符串
    if(str.empty()) {
        return 1;
    }
    size_t i = 0;
    string last_part;//当前部分的上一部分
    while(i < (str.size())) {
        if(str[i] == ' ') {
            i++;
        } else if((str[i] >= '0' && str[i] <= '9') || str[i] == '.') {//数字部分
            string t;
            int cnt_dec = 0;
            while((str[i] >= '0' && str[i] <= '9') || str[i] == '.') {
                if(str[i] == '.') {
                    cnt_dec++;
                }
                t += str[i];
                i++;
            }
            if(t.front() == '.' || t.back() == '.' || cnt_dec > 1) {//小数点不合法
                return 3;
            }
            if(last_part == "/" && stod(t) == 0.0) {//除0错误
                return 2;
            }
            last_part = t;//更新上一部分
        } else {//运算符部分
            if(last_part.empty() || last_part.back() < '0' || last_part.back() > '9') { //前一个不是数字或为空
                return 3;
            }
            last_part = string(1, str[i]);
            i++;
        }
    }
    return 0;
}

//中缀转后缀
QString Calculator::get_suffix(const QString &qstr) const {
    string str = qstr.toStdString();//转为标准字符串
    stack<string> st_oper;
    string ret;
    for (size_t i = 0; i < str.size(); i++) {
        if(str[i] == ' ') {
            i++;
        }
        if ((str[i] >= '0' && str[i] <= '9') || str[i] == '.') {
            size_t index_back = i + 1;
            while ((str[index_back] >= '0' && str[index_back] <= '9') || str[index_back] == '.') { //支持小数
                index_back++;
            }
            ret += str.substr(i, index_back - i) + " ";//数字直接输出至后式
            i = index_back - 1;//注意每次循环结束的i++
        } else {
            string oper = string(1, str[i]); //运算符转为字符串,便于判断
            if ((oper == "+" || oper == "-") && str[i - 1] != '(') { //低优先级运算符向前弹栈直到栈空或遇左括号
                while (!st_oper.empty() && st_oper.top() != "(") {
                    ret += st_oper.top() + " ";
                    st_oper.pop();
                }
                st_oper.push(oper);//低优先级运算符最后要入栈
            } else if (oper == "*" || oper == "/" || oper == "(") {//高优先级的运算符直接入栈
                st_oper.push(oper);
            } else if (oper == ")") {//开始匹配左括号
                while (st_oper.top() != "(") {
                    ret += st_oper.top() + " ";//括号之间栈内的运算符输出
                    st_oper.pop();
                }
                st_oper.pop();//记得最后弹出左括号,但不要输出至后缀式
            }
        }
    }
    while (!st_oper.empty()) {//弹出栈内最后剩余运算符
        ret += st_oper.top();
        if (st_oper.size() != 1) {
            ret += " ";
        }
        st_oper.pop();
    }
    return QString::fromStdString(ret);
}

//后缀计算结果
QString Calculator::get_result(const QString &qstr) const {
    string str = qstr.toStdString();//转为标准字符串
    stack<double> st_num;
    for(size_t i = 0; i < str.size(); i++) {
        while (str[i] == ' ') {
            i++;
        }
        string t;
        while(str[i] != ' ') {
            t += str[i];
            i++;
        }
        double num_a, num_b;
        switch (t[0]) {
            case '+':
                num_a = st_num.top();
                st_num.pop();
                num_b = st_num.top();
                st_num.pop();
                st_num.push(num_a + num_b);
                break;
            case '-':
                num_a = st_num.top();
                st_num.pop();
                num_b = st_num.top();
                st_num.pop();
                st_num.push(num_b - num_a);
                break;
            case '*':
                num_a = st_num.top();
                st_num.pop();
                num_b = st_num.top();
                st_num.pop();
                st_num.push(num_a * num_b);
                break;
            case '/':
                num_a = st_num.top();
                st_num.pop();
                num_b = st_num.top();
                st_num.pop();
                st_num.push(num_b / num_a);
                break;
            default:
                st_num.push(stod(t));//普通数字
                break;
        }
    }
    return QString::number(st_num.top());
}

Calculator::~Calculator() {
    delete ui;
}

main函数没有做出改变

#include "Calculator.h"
#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    Calculator w;
    w.show();//显示窗体
    return a.exec();//阻塞
}

5、程序导出与缺陷

有的功能不好靠截图展示出来,例如清屏和退格

所以我绑定了dll,导出了程序exe,并发送成了csdn的资源,可以运行看看,当然是免费的,0 C币 这是链接

目前的程序有很多缺陷,也可以说是功能不完全,以后可能周六日慢慢写吧

1、不支持负数和括号的输入
2、百分号、平方等特殊的按键运算只能用在表达式结果中,不能用在表达式输入中
3、表达式格式检验时,错误类型少,不能很好的提示表达式输入错误的类型

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值