QT实现计算器

代码

widget.h

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPushButton>
#include <QGridLayout>
#include <QSizePolicy>
#include <QLineEdit>
#include <QDebug>
#include <QtGlobal>
#include <QStack>
#include <cmath>

class Widget : public QWidget
{
    Q_OBJECT
    QLineEdit *edit = new QLineEdit();
    bool m_clearOnNextInput; // 新增:标志位,下次输入是否清除内容
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
public slots:
    void onNumberButtonClicked(const QString &number);
    void onEqualClicked();
};
#endif // WIDGET_H

widget.cpp

cpp 复制代码
#include "widget.h"
#include <vector>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
     m_clearOnNextInput = false; // 初始状态:不清除
    QGridLayout *layout = new QGridLayout();
    //按钮
    QPushButton* pqb1= new QPushButton("1");
    QPushButton* pqb2= new QPushButton("2");
    QPushButton* pqb3= new QPushButton("3");
    QPushButton* pqb4= new QPushButton("4");
    QPushButton* pqb5= new QPushButton("5");
    QPushButton* pqb6= new QPushButton("6");
    QPushButton* pqb7= new QPushButton("7");
    QPushButton* pqb8= new QPushButton("8");
    QPushButton* pqb9= new QPushButton("9");
    QPushButton* pqb0= new QPushButton("0");
    QPushButton* pqb10= new QPushButton("+");
    QPushButton* pqb11= new QPushButton("-");
    QPushButton* pqb12= new QPushButton("*");
    QPushButton* pqb13= new QPushButton("/");
    QPushButton* pqb14= new QPushButton(".");
    QPushButton* pqb15= new QPushButton("=");

    pqb1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb5->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb6->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb7->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb8->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb9->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb10->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb11->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb12->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb13->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb14->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb15->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pqb0->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);



    layout->addWidget(pqb0,3,0);
    layout->addWidget(pqb1,2,0);
    layout->addWidget(pqb2,2,1);
    layout->addWidget(pqb3,2,2);
    layout->addWidget(pqb4,1,0);
    layout->addWidget(pqb5,1,1);
    layout->addWidget(pqb6,1,2);
    layout->addWidget(pqb7,0,0);
    layout->addWidget(pqb8,0,1);
    layout->addWidget(pqb9,0,2);
    layout->addWidget(pqb10,3,2);
    layout->addWidget(pqb11,0,3);
    layout->addWidget(pqb12,1,3);
    layout->addWidget(pqb13,2,3);
    layout->addWidget(pqb14,3,1);
    layout->addWidget(pqb15,3,3);


    edit->show();
    edit->setMaximumHeight(150);
    QGridLayout *layout1 = new QGridLayout(this);
    edit->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    edit->setReadOnly(true); // 禁止手动输入


    layout1->addLayout(layout,1,0,4,4);
    layout1->addWidget(edit,0,0,1,4);

    std::vector<QPushButton*> arr = {pqb0,pqb1,pqb2,pqb3,pqb4,pqb5,pqb6,pqb7,pqb8,
                                     pqb9,pqb10,pqb11,pqb12,pqb13,pqb14};

    for(auto &ele : arr){
        connect(ele, &QPushButton::clicked, this, [this,ele](){
            this->onNumberButtonClicked(ele->text());});
    }

    connect(pqb15, &QPushButton::clicked, this, &Widget::onEqualClicked);


}

Widget::~Widget()
{
}
// 槽函数实现:追加数字到显示框
void Widget::onNumberButtonClicked(const QString &number) {
    if (m_clearOnNextInput) {
        // 如果需要清除,则先清空显示框,再输入新数字
        edit->setText(number);
        m_clearOnNextInput = false; // 重置标志位(下次输入恢复追加)
    } else {
        // 不需要清除,则直接追加数字
        edit->setText(edit->text() + number);
    }
}


//等号计算
QString calculateSimpleExpression(const QString &expression);

void Widget::onEqualClicked() {
        QString expr = edit->text();  // 获取QLineEdit中的表达式
        QString result = calculateSimpleExpression(expr);

        edit->setText(result);  // 显示结果
        m_clearOnNextInput = true;
}
// 辅助函数:判断是否为运算符(仅支持 +-*/)
bool isOperator(const QChar &c) {
    return c == '+' || c == '-' || c == '*' || c == '/';
}

// 辅助函数:获取运算符优先级(乘除 > 加减)
int getPriority(const QChar &op) {
    if (op == '+' || op == '-') return 1;  // 优先级低
    if (op == '*' || op == '/') return 2;  // 优先级高
    return 0;
}

// 步骤1:中缀表达式转后缀表达式(无括号版本)
QVector<QString> infixToPostfix(const QString &expression) {
    QVector<QString> postfix;  // 存储后缀表达式
    QStack<QChar> opStack;     // 运算符栈
    QString numBuffer;         // 缓存数字(支持多位数和小数)

    for (int i = 0; i < expression.size(); ++i) {
        QChar c = expression[i];

        // 跳过空格
        if (c.isSpace()) continue;

        // 处理数字或小数点
        if (c.isDigit() || c == '.') {
            numBuffer += c;
        }
        // 处理运算符
        else if (isOperator(c)) {
            // 先将缓存的数字加入后缀表达式
            if (numBuffer.isEmpty()) {
                return {};  // 连续运算符(如"1++2"),返回错误
            }
            postfix.append(numBuffer);
            numBuffer.clear();

            // 弹出栈中优先级 >= 当前运算符的运算符
            while (!opStack.isEmpty() && getPriority(opStack.top()) >= getPriority(c)) {
                postfix.append(opStack.top());
                opStack.pop();
            }
            opStack.push(c);  // 当前运算符入栈
        }
        // 非法字符(非数字、非运算符、非小数点)
        else {
            return {};  // 含非法字符,返回错误
        }
    }

    // 处理最后一个数字
    if (numBuffer.isEmpty()) {
        return {};  // 表达式以运算符结尾(如"1+"),返回错误
    }
    postfix.append(numBuffer);

    // 弹出栈中剩余运算符
    while (!opStack.isEmpty()) {
        postfix.append(opStack.top());
        opStack.pop();
    }

    return postfix;
}

// 步骤2:计算后缀表达式结果
QString calculatePostfix(const QVector<QString> &postfix) {
    if (postfix.isEmpty()) return "错误";

    QStack<double> numStack;  // 数字栈

    for (const QString &token : postfix) {
        // 如果是数字,入栈
        if (!isOperator(token[0]) || (token.size() > 1 && token[0] == '-')) {
            bool ok;
            double num = token.toDouble(&ok);
            if (!ok) return "错误";  // 数字格式错误(如多小数点)
            numStack.push(num);
        }
        // 如果是运算符,计算
        else {
            if (numStack.size() < 2) return "错误";  // 操作数不足

            double b = numStack.pop();  // 注意顺序:后弹出的是第一个操作数
            double a = numStack.pop();
            double result = 0;

            if (token == "+") {
                result = a + b;
            } else if (token == "-") {
                result = a - b;
            } else if (token == "*") {
                result = a * b;
            } else if (token == "/") {
                if (qFuzzyCompare(b, 0.0)) return "错误";  // 除零错误
                result = a / b;
            }

            numStack.push(result);
        }
    }

    // 最终栈中应只有一个结果
    if (numStack.size() != 1) return "错误";

    // 优化显示:整数去掉".0"
    double finalResult = numStack.pop();
    if (finalResult == floor(finalResult)) {
        return QString::number((long long)finalResult);  // 整数显示
    } else {
        return QString::number(finalResult);  // 小数显示
    }
}

// 对外接口:计算无括号的表达式
QString calculateSimpleExpression(const QString &expression) {
    // 空表达式处理
    if (expression.trimmed().isEmpty()) return "";

    // 中缀转后缀
    QVector<QString> postfix = infixToPostfix(expression);
    if (postfix.isEmpty()) return "错误";  // 转换失败(格式错误)

    // 计算结果
    return calculatePostfix(postfix);
}

测试结果

相关推荐
掘根2 小时前
【Qt】常用控件3——显示类控件
开发语言·数据库·qt
GUIQU.2 小时前
【QT】嵌入式开发:从零开始,让硬件“活”起来的魔法之旅
java·数据库·c++·qt
西阳未落6 小时前
C++基础(21)——内存管理
开发语言·c++·面试
我的xiaodoujiao6 小时前
Windows系统Web UI自动化测试学习系列2--环境搭建--Python-PyCharm-Selenium
开发语言·python·测试工具
callJJ6 小时前
从 0 开始理解 Spring 的核心思想 —— IoC 和 DI(2)
java·开发语言·后端·spring·ioc·di
hsjkdhs8 小时前
万字详解C++之构造函数析构函数
开发语言·c++
Lin_Aries_04219 小时前
容器化简单的 Java 应用程序
java·linux·运维·开发语言·docker·容器·rpc
techdashen9 小时前
12分钟讲解Python核心理念
开发语言·python
山海不说话9 小时前
Java后端面经(八股——Redis)
java·开发语言·redis