一、项目概述
在学习 Qt 桌面开发的过程中,计算器项目是经典的入门实战项目,既能巩固 Qt 核心机制,又能快速实现可视化效果。本文将完整记录一款支持四则运算、括号运算、界面美化的 Qt 计算器项目,从 UI 设计、逻辑实现、问题排查到打包发布,全程可复现,适合 Qt 入门学习与面试项目展示。
技术栈
- 开发语言:C++
- 开发框架:Qt 5.8.0(Qt Widgets 模块)
- 构建工具:qmake
- 开发环境:Qt Creator
- 核心技术:信号与槽、QString 字符串处理、UI 布局、QSS 样式美化、表达式解析
项目功能
- 0-9 数字、小数点输入
- 加减乘除四则运算、括号优先级运算
- 清零、退格、等于计算功能
- 现代化 UI 美化(圆角按钮、hover 效果、主题配色)
- 窗口标题自定义、字体样式设置
项目展示

二、项目开发流程
1. 新建项目与 UI 设计
(1)新建 Qt Widgets 项目
打开 Qt Creator,选择「Application → Qt Widgets Application」,项目名命名为NiceCalculator,基类选择QWidget,完成项目创建。
(2)UI 界面布局
双击widget.ui进入 Qt Designer 设计界面,按以下步骤完成布局:
- 顶部添加 1 个
QLineEdit作为输入显示框,设置objectName为lineEdit,勾选readOnly(只读,禁止手动输入),设置右对齐显示。 - 下方添加 19 个
QPushButton,按计算器布局排列,按钮objectName统一规范命名:- 数字:
btn0~btn9、btnDot(小数点) - 运算符:
btnAdd(+)、btnSub(-)、btnMul(*)、btnDiv(/)、btnLeft(()、btnRight()) - 功能键:
btnClear(清空)、btnDel(删除)、btnEqual(等于)
- 数字:
- 全选按钮,右键选择「Layout → Grid Layout」自动排版,选中整个窗口右键「Lay Out Vertically」,实现界面自适应。
2. 核心代码实现
(1)头文件widget.h
定义类、槽函数与成员变量,声明所有按钮的点击事件:
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QString>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
// 数字按钮槽函数
private slots:
void on_btn0_clicked();
void on_btn1_clicked();
void on_btn2_clicked();
void on_btn3_clicked();
void on_btn4_clicked();
void on_btn5_clicked();
void on_btn6_clicked();
void on_btn7_clicked();
void on_btn8_clicked();
void on_btn9_clicked();
void on_btnDot_clicked();
// 运算符按钮槽函数
void on_btnAdd_clicked();
void on_btnSub_clicked();
void on_btnMul_clicked();
void on_btnDiv_clicked();
void on_btnLeft_clicked();
void on_btnRight_clicked();
// 功能按钮槽函数
void on_btnClear_clicked();
void on_btnDel_clicked();
void on_btnEqual_clicked();
private:
Ui::Widget *ui;
QString expression; // 存储用户输入的表达式
};
#endif // WIDGET_H
(2)源文件widget.cpp
实现按钮逻辑、界面初始化、表达式计算与 UI 美化:
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QScriptEngine>
#include <QFont>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 窗口基础设置
setWindowTitle("cmh计算器");
setFixedSize(340, 460); // 固定窗口大小,禁止拉伸
// 输入框字体设置
QFont f("Microsoft YaHei", 22, QFont::Bold);
ui->lineEdit->setFont(f);
ui->lineEdit->setAlignment(Qt::AlignRight);
// QSS全局样式美化
this->setStyleSheet(R"(
QWidget { background:#f5f7fa; }
QLineEdit {
border:none; border-radius:12px;
padding:16px; background:#fff;
margin-bottom:10px;
}
QPushButton {
font-size:16px; border:none;
border-radius:18px; background:#fff;
min-height:45px;
}
QPushButton:hover { background:#e6e8ed; }
QPushButton#btnClear,QPushButton#btnDel{
background:#ff7878; color:white;
}
QPushButton#btnClear:hover,QPushButton#btnDel:hover{
background:#ff5252;
}
QPushButton#btnEqual{
background:#4285F4; color:white; font-weight:bold;
}
QPushButton#btnEqual:hover{
background:#3367D6;
}
)");
}
Widget::~Widget()
{
delete ui;
}
// 数字按钮点击逻辑:拼接表达式
void Widget::on_btn0_clicked() { expression += "0"; ui->lineEdit->setText(expression); }
void Widget::on_btn1_clicked() { expression += "1"; ui->lineEdit->setText(expression); }
void Widget::on_btn2_clicked() { expression += "2"; ui->lineEdit->setText(expression); }
void Widget::on_btn3_clicked() { expression += "3"; ui->lineEdit->setText(expression); }
void Widget::on_btn4_clicked() { expression += "4"; ui->lineEdit->setText(expression); }
void Widget::on_btn5_clicked() { expression += "5"; ui->lineEdit->setText(expression); }
void Widget::on_btn6_clicked() { expression += "6"; ui->lineEdit->setText(expression); }
void Widget::on_btn7_clicked() { expression += "7"; ui->lineEdit->setText(expression); }
void Widget::on_btn8_clicked() { expression += "8"; ui->lineEdit->setText(expression); }
void Widget::on_btn9_clicked() { expression += "9"; ui->lineEdit->setText(expression); }
void Widget::on_btnDot_clicked() { expression += "."; ui->lineEdit->setText(expression); }
// 运算符按钮点击逻辑
void Widget::on_btnAdd_clicked() { expression += "+"; ui->lineEdit->setText(expression); }
void Widget::on_btnSub_clicked() { expression += "-"; ui->lineEdit->setText(expression); }
void Widget::on_btnMul_clicked() { expression += "*"; ui->lineEdit->setText(expression); }
void Widget::on_btnDiv_clicked() { expression += "/"; ui->lineEdit->setText(expression); }
void Widget::on_btnLeft_clicked() { expression += "("; ui->lineEdit->setText(expression); }
void Widget::on_btnRight_clicked() { expression += ")"; ui->lineEdit->setText(expression); }
// 清空按钮
void Widget::on_btnClear_clicked()
{
expression.clear();
ui->lineEdit->clear();
}
// 退格按钮
void Widget::on_btnDel_clicked()
{
expression.chop(1);
ui->lineEdit->setText(expression);
}
// 等于按钮:表达式计算
void Widget::on_btnEqual_clicked()
{
QScriptEngine eng;
QScriptValue val = eng.evaluate(expression);
// 异常处理:表达式错误提示
if(eng.hasUncaughtException()){
ui->lineEdit->setText("Error");
expression.clear();
}else{
// 显示结果,支持连续运算
expression = val.toString();
ui->lineEdit->setText(expression);
}
}
(3)项目配置文件NiceCalculator.pro
添加script模块依赖,支持QScriptEngine表达式计算:
cpp
QT += core gui widgets script
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
三、项目难点与踩坑总结
1. 编译报错:'QString' does not name a type
问题原因 :头文件未包含 <QString>,或类名拼写错误(写成 Qstring 小写 s)。解决方案 :在 widget.h 中添加 #include <QString>,确保类名 QString 大小写正确。
2. 编译报错:QScriptEngine: No such file or directory
问题原因 :Qt 5 中 QScriptEngine 属于 script 模块,未在 .pro 文件中添加依赖。解决方案 :在 .pro 文件中添加 QT += script,执行 qmake 后重新编译。
3. 编译报错:stray '\357' in program
问题原因 :代码中混入了中文全角空格 / 不可见字符,导致编译器语法解析失败。解决方案:删除问题行,使用英文半角输入法重新输入,全程切换英文输入法编写代码。
4. 窗口标题修改不生效
问题原因 :代码中 setWindowTitle 优先级高于 UI 中的 windowTitle 属性,代码覆盖了 UI 设置。解决方案 :二选一修改,要么在 UI 中修改 windowTitle,要么在代码中修改,避免冲突。
5. 中文乱码问题
问题原因 :源文件编码非 UTF-8,导致中文显示乱码。解决方案 :在 Qt Creator 中设置文件编码为 UTF-8,代码中使用 QString::fromUtf8("中文") 包裹中文。
四、项目总结与收获
项目收获
- 掌握 Qt 核心机制:深入理解了 Qt 信号与槽、事件驱动编程、UI 布局等核心概念,熟悉了 Qt 项目的完整开发流程。
- 提升 C++ 编程能力:通过字符串处理、表达式计算、异常处理等逻辑,强化了 C++ 基础编程能力。
- 学会界面开发与美化:掌握了 Qt Designer 可视化布局、QSS 样式表美化、自定义图标等界面开发技巧。
- 培养问题排查能力:通过解决编译报错、逻辑 bug 等问题,提升了代码调试和问题排查能力。
后续优化方向
- 支持负数运算,增加科学计算器功能(开方、平方、三角函数等)
- 增加历史记录查询、表达式编辑功能
- 适配深色模式、多主题切换
- 打包为单文件 exe,提升分发便捷性