QT计算器开发

news2025/3/31 7:16:01

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_H

3.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.清除按钮:清空expressionmainLineEdit

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栈存储运算符。

  • 解析流程

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

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

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

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

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

    6. 如果遇到非法字符,返回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(表示错误)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2323874.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

R语言对偏态换数据进行转换(对数、平方根、立方根)

我们进行研究的时候经常会遇见偏态数据&#xff0c;数据转换是统计分析和数据预处理中的一项基本技术。使用 R 时&#xff0c;了解如何正确转换数据有助于满足统计假设、标准化分布并提高分析的准确性。在 R 中实现和可视化最常见的数据转换&#xff1a;对数、平方根和立方根转…

【云服务器】在 Linux(Ubuntu / CentOS 7)上快速搭建我的世界 Minecraft 服务器,并实现远程联机,详细教程

【云服务器】在 Linux&#xff08;Ubuntu / CentOS 7&#xff09;上快速搭建我的世界 Minecraft 服务器&#xff0c;并实现远程联机&#xff0c;详细教程 一、 服务器介绍二、下载 Minecraft 服务端二、安装 JRE 21三、安装 MCS manager 面板四、搭建服务器五、本地测试连接六、…

docker torcherve打包mar包并部署模型

使用Docker打包深度网络模型mar包到服务端 参考链接&#xff1a;Docker torchserve 部署模型流程——以WSL部署YOLO-FaceV2为例_class myhandler(basehandler): def initialize(self,-CSDN博客 1、docker拉取环境镜像命令 docker images出现此提示为没有权限取执行命令&…

【安当产品应用案例100集】042-基于安当KADP实现机密文件安全流转

一、客户需求 某集团公司客户&#xff0c;在系统业务流中&#xff0c;存在大量的内部文件流转的需求。内部业务文件有不同的安全密级&#xff0c;最初在文件流转时&#xff0c;公司内部规定点对点的文件传输&#xff0c;要使用加密工具加密后再发给需要的一方。这种方式虽然能…

附录C SLAC匹配过程命令定义与实际抓包

附录C SLAC匹配过程命令定义与实际抓包 ISO15118-3 附录A中规定了SLAC匹配过程中的请求命令及应答&#xff0c; 本文将会对比协议中的定义和实际抓包内容&#xff0c;以便读者获得直观的认识。 1 CM_SET_KEY.REQ 定义内容&#xff1a; 实际数据&#xff1a; 注意报文中的 08…

【QT】新建QT工程(详细步骤)

新建QT工程 1.方法(1)点击new project按钮&#xff0c;弹出对话框&#xff0c;新建即可&#xff0c;步骤如下&#xff1a;(2) 点击文件菜单&#xff0c;选择新建文件或者工程&#xff0c;后续步骤如上 2.QT工程文件介绍(1).pro文件 --》QT工程配置文件(2)main.cpp --》QT工程主…

安装Webpack并创建vue项目

1、新建一个工程目录 在E盘中进行新建项目 2、从命令行进入该目录,并执行NPM 的初始化命令 3、会看到目录中生成了一个“package.json”文件,它相当于NPM项目的说明书&#xff0c;里面记录了项目名称、版本、仓库地址等信息。 4、执行安装 Webpack 的命令 npm install webpac…

如何快速解决django存储session变量时出现的django.db.utils.DatabaseError错误

我们在学习django进行web编程的时候&#xff0c;有时需要将一些全局变量信息存储在session中&#xff0c;但使用过程中&#xff0c;却发现会引起数据库的报错。通过查看django源码信息&#xff0c;发现其对session信息进行了ORM映射&#xff0c;如果数据库中不存在对应的表信息…

04 单目标定实战示例

看文本文,您将获得以下技能: 1:使用opencv进行相机单目标定实战 2:标定结果参数含义和数值分析 3:Python绘制各标定板姿态,查看图像采集多样性 4:如果相机画幅旋转90,标定输入参数该如何设置? 5:图像尺寸缩放,标定结果输出有何影响? 6:单目标定结果应用类别…

极速全场景 MPP数据库starrocks介绍

目录 一、引子 二、起源 &#xff08;一&#xff09;前身 &#xff08;二&#xff09;定位 三、特点 &#xff08;一&#xff09;高性能架构 &#xff08;二&#xff09;实时分析 &#xff08;三&#xff09;高并发与扩展性 &#xff08;四&#xff09;兼容性与生态 …

RS232转Profinet网关技术,检漏仪新篇章!

RS232转Profinet网关技术&#xff0c;检漏仪新篇章&#xff01; 在现代医疗监控系统中&#xff0c;RS232转PROFINET网关扮演着至关重要的角色。这种转换设备能够将传统的RS232串行通讯接口无缝转换为PROFINET以太网通信接口&#xff0c;确保老旧设备与现代自动化系统之间的顺畅…

Linux操作系统7- 线程同步与互斥7(RingQueue环形队列生产者消费者模型改进)

上篇文章&#xff1a;Linux操作系统7- 线程同步与互斥6&#xff08;POSIX信号量与环形队列生产者消费者模型&#xff09;-CSDN博客 本篇代码仓库&#xff1a;myLerningCode/l36 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com) 目录 一. 单生产单消费单保…

将 Markdown 表格结构转换为Excel 文件

在数据管理和文档编写过程中&#xff0c;我们经常使用 Markdown 来记录表格数据。然而&#xff0c;Markdown 格式的表格在实际应用中不如 Excel 方便&#xff0c;特别是需要进一步处理数据时。因此&#xff0c;我们开发了一个使用 wxPython 的 GUI 工具&#xff0c;将 Markdown…

微信小程序逆向开发

一.wxapkg文件 如何查看微信小程序包文件&#xff1a; 回退一级 点击进入这个目录 这个就是我们小程序对应的文件 .wxapkg概述 .wxapkg是微信小程序的包文件格式&#xff0c;且其具有独特的结构和加密方式。它不仅包含了小程序的源代码&#xff0c;还包括了图像和其他资源文…

Spring Data审计利器:@LastModifiedDate详解!!!

&#x1f552; Spring Data审计利器&#xff1a;LastModifiedDate详解&#x1f525; &#x1f31f; 简介 在数据驱动的应用中&#xff0c;记录数据的最后修改时间是常见需求。Spring Data的LastModifiedDate注解让这一过程自动化成为可能&#xff01;本篇带你掌握它的核心用法…

wms窗口/多窗口/自由窗口systemui侧边栏手势退出实战-学员作业

背景&#xff1a; 再学习了马哥的分屏自由窗口专题课程时候&#xff0c;有一个需求就是实现自由窗口置顶的功能&#xff0c;这个需求实现后&#xff0c;自由窗口就会一直处于顶端&#xff0c;不会因为打开其他Activity导致自由窗口退出。 不会因为打开了其他Activity而导致短…

服装零售行业数据分析方案

在数据洪流的时代&#xff0c;大数据分析已成为服装产业的强大引擎&#xff0c;助力企业飞速提升运营效率&#xff0c;削减成本&#xff0c;并优化资源配置。在服饰行业的生产运营链中&#xff0c;商业智能&#xff08;BI&#xff09;工具扮演着至关重要的角色&#xff0c;它们…

基于大模型的pc版语音对话问答

Vosk基础知识&#xff1a; Vosk 是一个强大的开源语音识别工具包&#xff0c;以下是对它的详细介绍&#xff1a; 特点 离线识别&#xff1a;Vosk 的显著特点是支持离线语音识别。这意味着在没有网络连接的情况下&#xff0c;也能进行语音识别操作&#xff0c;避免了因网络问…

深入理解 Linux 内核中的 GPU 子系统:从 DRM 到 NXP 驱动架构全解读

本文不仅为 GPU 子系统的深入复习笔记&#xff0c;更是一本面向 Linux 内核开发者、嵌入式图形系统开发人员的实践指南。本文围绕 drivers/gpu 展开&#xff0c;特别聚焦 NXP i.MX 系列平台的 GPU 架构和 Linux-imx 的实现方式&#xff0c;内容超 5000 字&#xff0c;适合收藏学…

Allegro界面颜色改变设置

概述&#xff1a;本文主要讲解如何改变allegro的背景颜色&#xff0c;改为自己喜欢的颜色 1、 打开Allegro文件 2、 Setup—User Preference—UI—General—Allegro_theme选择Light即可 改变前 改变后