Qt 作为跨平台的 C++ 图形界面开发框架,凭借其简洁的 API 和强大的信号槽机制,非常适合开发桌面应用。本文将手把手教你实现一个具备基础四则运算(加减乘除)、清空、退格功能的计算器,涵盖 Qt 界面布局、样式美化、信号槽绑定、表达式解析等核心知识点。

一、项目整体结构

本次开发的计算器项目包含 3 个核心文件,职责分工清晰:

文件名称 作用
calculator.h 计算器类的头文件,定义类结构、成员变量和槽函数声明
calculator.cpp 计算器类的实现文件,完成界面初始化、样式美化、逻辑处理
main.cpp 程序入口,创建应用程序对象并显示计算器窗口

二、核心开发步骤

步骤 1:头文件设计(calculator.h)

首先定义Calculator类,继承自QWidget(Qt 基础窗口类),核心包含:

  • 成员变量:显示框(QLineEdit)、运算表达式(QString
  • 槽函数:处理按钮点击、清空、退格、计算逻辑
  • 私有方法:初始化界面、初始化样式表
#ifndef CALCULATOR_H
#define CALCULATOR_H

#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QGridLayout>
#include <QString>

class Calculator : public QWidget
{
    Q_OBJECT // 必须添加,启用Qt信号槽机制

public:
    Calculator(QWidget *parent = nullptr);
    ~Calculator() = default;

private slots:
    // 数字/运算符按钮点击槽函数
    void onButtonClicked();
    // 清空显示框
    void onClearClicked();
    // 退格(删除最后一个字符)
    void onBackspaceClicked();
    // 计算结果
    void onCalculateClicked();

private:
    QLineEdit *m_display; // 显示输入/结果的文本框
    QString m_expression; // 存储用户输入的运算表达式
    // 初始化界面布局和控件
    void initUI();
    // 初始化控件样式表
    void initStyle();
};

#endif // CALCULATOR_H

步骤 2:界面初始化(calculator.cpp - initUI 方法)

计算器界面采用QGridLayout(网格布局)实现,优势是能精准控制控件的行列位置,贴合计算器的布局特点。

核心逻辑:
  • 显示框配置:设置右对齐、只读、放大字体,禁止手动输入(仅通过按钮触发);
  • 按钮创建:按计算器布局创建数字、运算符、功能按钮;
  • 网格布局:将显示框、按钮添加到网格,设置间距和内边距;
  • 信号槽绑定:数字 / 运算符按钮绑定通用槽函数,功能按钮绑定专属槽函数。
#include "calculator.h"
#include <QDebug>
#include <QRegExp>
#include <cmath>

Calculator::Calculator(QWidget *parent)
    : QWidget(parent),
      m_display(new QLineEdit(this)),
      m_expression("")
{
    initUI();    // 初始化界面布局
    initStyle(); // 初始化样式表
}

// 初始化界面:布局+控件创建+信号槽绑定
void Calculator::initUI()
{
    // 1. 显示框属性配置
    m_display->setAlignment(Qt::AlignRight); // 右对齐
    m_display->setReadOnly(true); // 只读,禁止手动输入
    m_display->setFont(QFont("微软雅黑", 18)); // 字体放大
    m_display->setMinimumHeight(60); // 设置最小高度

    // 2. 创建所有按钮
    QPushButton *btnAC = new QPushButton("AC", this);
    QPushButton *btnBack = new QPushButton("←", this);
    QPushButton *btnDiv = new QPushButton("÷", this);
    QPushButton *btnMul = new QPushButton("×", this);
    QPushButton *btn7 = new QPushButton("7", this);
    QPushButton *btn8 = new QPushButton("8", this);
    QPushButton *btn9 = new QPushButton("9", this);
    QPushButton *btnSub = new QPushButton("-", this);
    QPushButton *btn4 = new QPushButton("4", this);
    QPushButton *btn5 = new QPushButton("5", this);
    QPushButton *btn6 = new QPushButton("6", this);
    QPushButton *btnAdd = new QPushButton("+", this);
    QPushButton *btn1 = new QPushButton("1", this);
    QPushButton *btn2 = new QPushButton("2", this);
    QPushButton *btn3 = new QPushButton("3", this);
    QPushButton *btnEqual = new QPushButton("=", this);
    QPushButton *btn0 = new QPushButton("0", this);
    QPushButton *btnDot = new QPushButton(".", this);

    // 3. 网格布局配置
    QGridLayout *mainLayout = new QGridLayout(this);
    mainLayout->setSpacing(8); // 控件间距
    mainLayout->setContentsMargins(15, 15, 15, 15); // 布局内边距

    // 4. 添加控件到网格(行、列、占用行、占用列)
    mainLayout->addWidget(m_display, 0, 0, 1, 4); // 显示框跨4列
    mainLayout->addWidget(btnAC, 1, 0);
    mainLayout->addWidget(btnBack, 1, 1);
    mainLayout->addWidget(btnDiv, 1, 2);
    mainLayout->addWidget(btnMul, 1, 3);
    mainLayout->addWidget(btn7, 2, 0);
    mainLayout->addWidget(btn8, 2, 1);
    mainLayout->addWidget(btn9, 2, 2);
    mainLayout->addWidget(btnSub, 2, 3);
    mainLayout->addWidget(btn4, 3, 0);
    mainLayout->addWidget(btn5, 3, 1);
    mainLayout->addWidget(btn6, 3, 2);
    mainLayout->addWidget(btnAdd, 3, 3);
    mainLayout->addWidget(btn1, 4, 0);
    mainLayout->addWidget(btn2, 4, 1);
    mainLayout->addWidget(btn3, 4, 2);
    mainLayout->addWidget(btnEqual, 4, 3, 2, 1); // 等号跨2行
    mainLayout->addWidget(btn0, 5, 0, 1, 2); // 0跨2列
    mainLayout->addWidget(btnDot, 5, 2);

    // 5. 信号槽绑定
    // 数字/运算符按钮绑定通用槽函数
    QList<QPushButton*> btnList = {btn0,btn1,btn2,btn3,btn4,btn5,btn6,btn7,btn8,btn9,
                                   btnAdd,btnSub,btnMul,btnDiv,btnDot};
    for (QPushButton *btn : btnList) {
        connect(btn, &QPushButton::clicked, this, &Calculator::onButtonClicked);
    }
    // 功能按钮绑定专属槽函数
    connect(btnAC, &QPushButton::clicked, this, &Calculator::onClearClicked);
    connect(btnBack, &QPushButton::clicked, this, &Calculator::onBackspaceClicked);
    connect(btnEqual, &QPushButton::clicked, this, &Calculator::onCalculateClicked);

    // 设置窗口固定大小
    this->setFixedSize(300, 400);
    this->setWindowTitle("Qt计算器");
}

步骤 3:样式美化(calculator.cpp - initStyle 方法)

通过 Qt 样式表(QSS)美化控件,实现圆角、hover / 按下状态、功能按钮差异化配色,提升界面质感。

// 初始化样式表:美化显示框、按钮
void Calculator::initStyle()
{
    // 显示框样式:圆角、边框、背景色
    m_display->setStyleSheet(R"(
        QLineEdit {
            background-color: #f8f9fa;
            border: 2px solid #ced4da;
            border-radius: 8px;
            padding-right: 10px;
            color: #212529;
        }
    )");

    // 全局按钮样式 + 差异化配色
    this->setStyleSheet(R"(
        QPushButton {
            font: bold 16px "微软雅黑";
            background-color: #e9ecef;
            border: none;
            border-radius: 8px;
            color: #212529;
            min-height: 40px;
        }
        QPushButton:hover { /* 鼠标悬停 */
            background-color: #dee2e6;
        }
        QPushButton:pressed { /* 按钮按下 */
            background-color: #adb5bd;
        }
        /* 运算符按钮:黄色系 */
        QPushButton[text="+"], QPushButton[text="-"],
        QPushButton[text="×"], QPushButton[text="÷"] {
            background-color: #ffc107;
            color: white;
        }
        QPushButton[text="+"]:hover, QPushButton[text="-"]:hover,
        QPushButton[text="×"]:hover, QPushButton[text="÷"]:hover {
            background-color: #ffca2c;
        }
        /* 等号按钮:绿色系 */
        QPushButton[text="="] {
            background-color: #28a745;
            color: white;
        }
        QPushButton[text="="]:hover {
            background-color: #20c997;
        }
        /* 功能按钮:红色系 */
        QPushButton[text="AC"], QPushButton[text="←"] {
            background-color: #dc3545;
            color: white;
        }
        QPushButton[text="AC"]:hover, QPushButton[text="←"]:hover {
            background-color: #e55353;
        }
    )");
}

步骤 4:业务逻辑实现(calculator.cpp)

4.1 数字 / 运算符输入(onButtonClicked)

获取点击按钮的文本,拼接成运算表达式并显示在输入框中。

// 数字/运算符按钮点击:拼接表达式并显示
void Calculator::onButtonClicked()
{
    QPushButton *btn = qobject_cast<QPushButton*>(sender()); // 获取点击的按钮
    if (!btn) return;
    QString text = btn->text();
    m_expression += text; // 拼接表达式
    m_display->setText(m_expression); // 显示到输入框
    qDebug() << "当前表达式:" << m_expression; // 调试输出
}
4.2 清空与退格(onClearClicked/onBackspaceClicked)
  • 清空:重置表达式和显示框;
  • 退格:删除表达式最后一个字符。
// 清空:重置表达式和显示框
void Calculator::onClearClicked()
{
    m_expression.clear();
    m_display->clear();
    qDebug() << "已清空表达式";
}

// 退格:删除最后一个字符
void Calculator::onBackspaceClicked()
{
    if (!m_expression.isEmpty()) {
        m_expression.chop(1); // 移除最后一个字符
        m_display->setText(m_expression);
        qDebug() << "退格后表达式:" << m_expression;
    }
}
4.3 运算逻辑(onCalculateClicked)

核心逻辑:解析表达式,替换 Qt 显示的×/÷为 C++ 识别的*/,通过正则匹配提取数字和运算符,执行四则运算,并处理除零错误、表达式错误等异常。

// 计算结果:解析表达式,完成加减乘除运算
void Calculator::onCalculateClicked()
{
    if (m_expression.isEmpty()) return;
    // 替换×为*、÷为/,适配C++运算规则
    QString expr = m_expression;
    expr.replace("×", "*").replace("÷", "/");
    qDebug() << "解析后的运算表达式:" << expr;

    // 正则匹配:数字+运算符+数字 格式(支持小数)
    QRegExp regExp("(\\d+\\.?\\d*)\\s*([+\\-*/])\\s*(\\d+\\.?\\d*)");
    if (regExp.indexIn(expr) != -1) {
        double num1 = regExp.cap(1).toDouble(); // 第一个数字
        QString op = regExp.cap(2);             // 运算符
        double num2 = regExp.cap(3).toDouble(); // 第二个数字
        double result = 0.0;

        // 执行运算
        if (op == "+") result = num1 + num2;
        else if (op == "-") result = num1 - num2;
        else if (op == "*") result = num1 * num2;
        else if (op == "/") {
            if (qFuzzyCompare(num2, 0.0)) { // 防止除零(浮点精度处理)
                m_display->setText("错误:除零");
                m_expression.clear();
                return;
            }
            result = num1 / num2;
        }

        // 显示结果:移除末尾多余的0和小数点
        QString resText = QString::number(result, 'f', 6).remove(QRegExp("\\.?0+$"));
        m_display->setText(resText);
        // 结果作为下一次运算的初始值
        m_expression = resText;
        qDebug() << "运算结果:" << num1 << op << num2 << "=" << result;
    } else {
        m_display->setText("表达式错误");
        m_expression.clear();
        qDebug() << "表达式格式错误:" << expr;
    }
}

步骤 5:程序入口(main.cpp)

创建 Qt 应用程序对象,实例化计算器窗口并显示,启动事件循环。

#include "calculator.h"
#include <QApplication>
#include<mainwindow.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Calculator w; // 计算器窗口
    w.show();     // 显示窗口
    w.setWindowTitle("chenchen");
    MainWindow m; // 可根据需求删除,本文核心为Calculator
    m.show();
    return a.exec(); // 运行Qt事件循环
}

三、运行结果

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐