QT实现四则运算计算器(QT实操1)
1.项目架构
1.图形化界面

2.widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QString>
#include <QStack>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void on_oneButton_clicked();
    void on_twoButton_clicked();
    void on_threeButton_clicked();
    void on_fourButton_clicked();
    void on_fiveButton_clicked();
    void on_sixButton_clicked();
    void on_sevenButton_clicked();
    void on_eightButton_clicked();
    void on_nineButton_clicked();
    void on_leftButton_clicked();
    void on_rightButton_clicked();
    void on_addButton_clicked();
    void on_reduceButton_clicked();
    void on_mulButton_clicked();
    void on_divButton_clicked();
    void on_zeroButton_clicked();
    void on_clearButton_clicked();
    void on_backButton_clicked();
    void on_equalButton_clicked();
    int evaluateExpression(const QString &expr);
    int applyOperator(double a, double b, QChar op);
private:
    Ui::Widget *ui;
    QString expression;
};
#endif // WIDGET_H3.main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}3.widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setMaximumSize(210,295);
    this->setMinimumSize(210,295);
    this->setWindowTitle("计算器");
    QFont f("仿宋",14);//字体对象
    ui->mainLineEdit->setFont(f);
    //按钮上放图片
    QIcon con("/data/wzh/QT/Qt_1/calculate/Back.png");
    ui->backButton->setIcon(con);
    //改变按钮背景色
    ui->equalButton->setStyleSheet("background:green");
}
Widget::~Widget()
{
    delete ui;
}
void Widget::on_oneButton_clicked()
{
    expression += "1";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_twoButton_clicked()
{
    expression += "2";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_threeButton_clicked()
{
    expression += "3";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_fourButton_clicked()
{
    expression += "4";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_fiveButton_clicked()
{
    expression += "5";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_sixButton_clicked()
{
    expression += "6";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_sevenButton_clicked()
{
    expression += "7";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_eightButton_clicked()
{
    expression += "8";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_nineButton_clicked()
{
    expression += "9";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_leftButton_clicked()
{
    expression += "(";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_rightButton_clicked()
{
    expression += ")";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_addButton_clicked()
{
    expression += "+";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_reduceButton_clicked()
{
    expression += "-";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_mulButton_clicked()
{
    expression += "*";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_divButton_clicked()
{
    expression += "/";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_zeroButton_clicked()
{
    expression += "0";
    ui->mainLineEdit->setText(expression);
}
void Widget::on_clearButton_clicked()
{
    expression.clear();
    ui->mainLineEdit->clear();
}
void Widget::on_backButton_clicked()
{
    expression.chop(1);
    ui->mainLineEdit->setText(expression);
}
void Widget::on_equalButton_clicked()
{
       // 获取表达式
       QString expr = ui->mainLineEdit->text();
       // 检查表达式是否为空
       if (expr.isEmpty()) {
           ui->mainLineEdit->setText("Error: Empty expression");
           return;
       }
       // 解析和计算表达式
       double result = evaluateExpression(expr);
       // 显示结果
       ui->mainLineEdit->setText(QString::number(result));
}
int Widget::evaluateExpression(const QString &expr)
{
    // 定义运算符优先级
    QMap<QChar, int> precedence;
    precedence['+'] = 1;
    precedence['-'] = 1;
    precedence['*'] = 2;
    precedence['/'] = 2;
    // 操作数栈
    QStack<double> values;
    // 运算符栈
    QStack<QChar> ops;
    int i = 0;
    while (i < expr.length()) {
        QChar c = expr[i];
        if (c.isDigit() || c == '.') {
            // 解析数字(包括小数)
            double val = 0;
            int j = i;
            bool hasDecimal = false;
            // 判断小数点错误
            while (j < expr.length() && (expr[j].isDigit() || expr[j] == '.')) {
                if (expr[j] == '.') {
                    if (hasDecimal) {
                        // 多个小数点,非法表达式
                        return 0;
                    }
                    hasDecimal = true;}
                j++;}
            // 提取数字字符串
            QString numStr = expr.mid(i, j - i);
            bool ok;
            val = numStr.toDouble(&ok);
            if (!ok) {
                return 0;} // 转换失败
            values.push(val);
            i = j;}
            else if (c == '(') {
            // 左括号直接入栈
            ops.push(c);
            i++;}
            else if (c == ')') {
            // 右括号,弹出运算符直到遇到左括号
            while (!ops.isEmpty() && ops.top() != '(') {
                double val2 = values.pop();
                double val1 = values.pop();
                QChar op = ops.pop();
                double res = applyOperator(val1, val2, op);
                values.push(res);}
            if (!ops.isEmpty()) {
                ops.pop();} // 弹出左括号
            i++;}
            else if (precedence.contains(c)) {
            // 处理运算符
            while (!ops.isEmpty() && ops.top() != '(' && precedence[ops.top()] >= precedence[c]) {
                double val2 = values.pop();
                double val1 = values.pop();
                QChar op = ops.pop();
                double res = applyOperator(val1, val2, op);
                values.push(res);}
            ops.push(c);
            i++;}
            else {
            // 非法字符
            return 0;}
    }
    // 处理剩余的运算符
    while (!ops.isEmpty()) {
        double val2 = values.pop();
        double val1 = values.pop();
        QChar op = ops.pop();
        double res = applyOperator(val1, val2, op);
        values.push(res);
    }
    return values.pop();
}
int Widget::applyOperator(double a, double b, QChar op)
{
    switch (op.toLatin1()) {
        case '+':
            return a + b;
        case '-':
            return a - b;
        case '*':
            return a * b;
        case '/':
            if (b == 0) {
                // 除以零错误
                return 0;
            }
            return a / b;
        default:
            return 0;
    }
}2. 程序讲解
-  主窗口类: Widget继承自QWidget,负责计算器的UI和逻辑。
-  UI文件:通过 ui_widget.h自动生成,包含计算器的界面元素(按钮、文本框等)。
-  核心功能: -  数字和运算符的输入 
-  表达式的解析和计算 
-  结果的显示 
 
-  
1. 初始化代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setMaximumSize(210,295);
    this->setMinimumSize(210,295);
    this->setWindowTitle("计算器");
    QFont f("仿宋",14);//字体对象
    ui->mainLineEdit->setFont(f);
    //按钮上放图片
    QIcon con("/data/wzh/QT/Qt_1/calculate/Back.png");
    ui->backButton->setIcon(con);
    //改变按钮背景色
    ui->equalButton->setStyleSheet("background:green");
}-  窗口设置: -  固定窗口大小为210x295像素。 
-  设置窗口标题为“计算器”。 
 
-  
-  字体设置: -  使用 QFont设置mainLineEdit的字体为“仿宋”,字号为14。
 
-  
-  按钮图标: -  为 backButton设置图片图标。
 
-  
-  按钮样式: -  为 equalButton设置背景颜色为绿色。
 
-  
2.按钮事件处理
1.数字按钮:每个数字按钮(0-9)将对应的数字添加到expression字符串中,并更新mainLineEdit的显示。
 
2.运算符按钮:+、-、*、/按钮将对应的运算符添加到expression中。
 
3.括号按钮:(和)按钮将括号添加到expression中。
 
void Widget::on_divButton_clicked()
{
    expression += "/";
    ui->mainLineEdit->setText(expression);
}4.清除按钮:清空expression和mainLineEdit。
 
void Widget::on_clearButton_clicked()
{
    expression.clear();
    ui->mainLineEdit->clear();
}5.退格按钮:删除expression的最后一个字符,并更新显示。
 
void Widget::on_backButton_clicked()
{
    expression.chop(1);
    ui->mainLineEdit->setText(expression);
}6.等号按钮:
void Widget::on_equalButton_clicked()
{
       // 获取表达式
       QString expr = ui->mainLineEdit->text();
       // 检查表达式是否为空
       if (expr.isEmpty()) {
           ui->mainLineEdit->setText("Error: Empty expression");
           return;
       }
       // 解析和计算表达式
       double result = evaluateExpression(expr);
       // 显示结果
       ui->mainLineEdit->setText(QString::number(result));
}-  获取 mainLineEdit中的表达式。
-  如果表达式为空,显示错误信息。 
-  调用 evaluateExpression计算结果,并显示结果。
3. 表达式解析和计算
int Widget::evaluateExpression(const QString &expr)
{
    // 定义运算符优先级
    QMap<QChar, int> precedence;
    precedence['+'] = 1;
    precedence['-'] = 1;
    precedence['*'] = 2;
    precedence['/'] = 2;
    // 操作数栈
    QStack<double> values;
    // 运算符栈
    QStack<QChar> ops;
    int i = 0;
    while (i < expr.length()) {
        QChar c = expr[i];
        if (c.isDigit() || c == '.') {
            // 解析数字(包括小数)
            double val = 0;
            int j = i;
            bool hasDecimal = false;
            // 判断小数点错误
            while (j < expr.length() && (expr[j].isDigit() || expr[j] == '.')) {
                if (expr[j] == '.') {
                    if (hasDecimal) {
                        // 多个小数点,非法表达式
                        return 0;
                    }
                    hasDecimal = true;}
                j++;}
            // 提取数字字符串
            QString numStr = expr.mid(i, j - i);
            bool ok;
            val = numStr.toDouble(&ok);
            if (!ok) {
                return 0;} // 转换失败
            values.push(val);
            i = j;}
            else if (c == '(') {
            // 左括号直接入栈
            ops.push(c);
            i++;}
            else if (c == ')') {
            // 右括号,弹出运算符直到遇到左括号
            while (!ops.isEmpty() && ops.top() != '(') {
                double val2 = values.pop();
                double val1 = values.pop();
                QChar op = ops.pop();
                double res = applyOperator(val1, val2, op);
                values.push(res);}
            if (!ops.isEmpty()) {
                ops.pop();} // 弹出左括号
            i++;}
            else if (precedence.contains(c)) {
            // 处理运算符
            while (!ops.isEmpty() && ops.top() != '(' && precedence[ops.top()] >= precedence[c]) {
                double val2 = values.pop();
                double val1 = values.pop();
                QChar op = ops.pop();
                double res = applyOperator(val1, val2, op);
                values.push(res);}
            ops.push(c);
            i++;}
            else {
            // 非法字符
            return 0;}
    }
    // 处理剩余的运算符
    while (!ops.isEmpty()) {
        double val2 = values.pop();
        double val1 = values.pop();
        QChar op = ops.pop();
        double res = applyOperator(val1, val2, op);
        values.push(res);
    }
    return values.pop();
}-  运算符优先级:使用 QMap定义运算符的优先级(+、-优先级为1,*、/优先级为2)。
-  栈结构: -  values栈存储操作数。
-  ops栈存储运算符。
 
-  
-  解析流程: -  遍历表达式中的每个字符。 
-  如果是数字或小数点,解析整个数字并压入 values栈。
-  如果是左括号 (,直接压入ops栈。
-  如果是右括号 ),弹出ops栈中的运算符直到遇到左括号,并计算结果。
-  如果是运算符,根据优先级处理 ops栈中的运算符,并将当前运算符压入栈。
-  如果遇到非法字符,返回0。 
 
-  
-  计算剩余运算符:处理完所有字符后,弹出 ops栈中的剩余运算符并计算结果。
4. 运算符应用
int Widget::applyOperator(double a, double b, QChar op)
{
    switch (op.toLatin1()) {
        case '+':
            return a + b;
        case '-':
            return a - b;
        case '*':
            return a * b;
        case '/':
            if (b == 0) {
                // 除以零错误
                return 0;
            }
            return a / b;
        default:
            return 0;
    }
}-  根据运算符执行对应的数学运算。 
-  如果是除法且除数为0,返回0(表示错误)。 
