QT计算器开发

1.项目架构

1.图形化界面

2.widget.h​

cpp 复制代码
#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_H

3.main.cpp​

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​

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. 初始化代码

cpp 复制代码
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中。

cpp 复制代码
void Widget::on_divButton_clicked()
{
    expression += "/";
    ui->mainLineEdit->setText(expression);
}

4.清除按钮 :清空expressionmainLineEdit

cpp 复制代码
void Widget::on_clearButton_clicked()
{
    expression.clear();
    ui->mainLineEdit->clear();
}

5.退格按钮 :删除expression的最后一个字符,并更新显示。

cpp 复制代码
void Widget::on_backButton_clicked()
{
    expression.chop(1);
    ui->mainLineEdit->setText(expression);
}

6.等号按钮

cpp 复制代码
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. 表达式解析和计算

cpp 复制代码
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栈存储运算符。

  • 解析流程

    1. 遍历表达式中的每个字符。

    2. 如果是数字或小数点,解析整个数字并压入values栈。

    3. 如果是左括号(,直接压入ops栈。

    4. 如果是右括号),弹出ops栈中的运算符直到遇到左括号,并计算结果。

    5. 如果是运算符,根据优先级处理ops栈中的运算符,并将当前运算符压入栈。

    6. 如果遇到非法字符,返回0。

  • 计算剩余运算符 :处理完所有字符后,弹出ops栈中的剩余运算符并计算结果。

4. 运算符应用

cpp 复制代码
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(表示错误)。

相关推荐
xyliiiiiL1 小时前
从责任链模式聊到aware接口
java·开发语言
Elec_z2 小时前
网络深处的守门人
开发语言·网络
闪电麦坤953 小时前
C#:Time.deltaTime
开发语言·c#
basketball6163 小时前
C++ STL常用算法之常用排序算法
c++·算法·排序算法
moz与京3 小时前
[附C++,JS,Python题解] Leetcode 面试150题(10)——轮转数组
c++·python·leetcode
Alfadi联盟 萧瑶5 小时前
Python-Django入手
开发语言·python·django
晚雾也有归处6 小时前
链表(C++)
数据结构·c++·链表
-代号95276 小时前
【JavaScript】十二、定时器
开发语言·javascript·ecmascript
勘察加熊人6 小时前
c++实现录音系统
开发语言·c++
self-discipline6346 小时前
【Java】Java核心知识点与相应面试技巧(七)——类与对象(二)
java·开发语言·面试