简介这是一份基于Qt框架开发的职工工资管理系统完整源码工程面向学习C与Qt桌面开发的学生及初级开发者可用于课程设计、毕业设计或自学练手。系统实现了录入、注册、登录、搜索、数据显示、修改、求取总工资与平均工资等核心功能并配有登录、注册、主界面、录入四个界面覆盖数据库读写与界面交互的典型场景。压缩包共73个文件、约21.3MB包含5个cpp源文件、4个h头文件与4个ui界面文件另有27个dll运行库、21个qm多语言翻译文件及1个db数据库文件exe可直接运行工程结构完整。目前已有1427人学习下载。读者可借此掌握Qt信号槽、SQLite数据库操作、多界面跳转与打包发布流程并参考现有代码进行二次开发。需注意db文件为空时会影响登录可自行添加数据或修改main直接进入主界面。1. 从一份 Qt 工资管理系统源码说起它到底能跑出什么如果你手头正躺着一个Qt_工资管理系统.zip双击解压后看到一堆.pro、.cpp、.ui文件却不知道从哪下手这篇拆解就是写给你的。这个项目本质上是一个基于 Qt 的桌面端工资管理工具核心场景很明确把员工信息、考勤数据、工资项配置、月度工资核算和工资条导出串成一条完整链路。它适合两类人——一类是刚学完 Qt 控件、想找一个能跑起来的完整项目练手的开发者另一类是需要快速交付一套内部工资核算工具、不想从零搭框架的熟手。工资管理系统听起来像课程设计但真正拆进去你会发现里面涉及数据库事务、表格模型映射、多条件查询、报表导出这些在业务系统里天天用的东西把它吃透比刷十个控件 Demo 都值。2. 项目定位与技术选型为什么用 Qt 做工资管理2.1 这个项目解决的真实问题工资管理这件事说小也小说麻烦也麻烦。一个几十人规模的小团队如果全靠 Excel 手工算每个月都要经历一遍“复制上月表格 → 改考勤 → 调社保基数 → 重新核对个税”的循环改错一个单元格整列数据全废。这个 Qt 工资管理系统要解决的就是把这条链路固化下来员工档案存库、考勤按月录入、工资项基本工资、绩效、补贴、扣款可配置、核算逻辑自动跑、结果能导出成表格给财务。从项目结构看它不是一个玩具级的单文件程序而是有清晰分层数据层负责 SQLite 读写模型层负责把数据库记录映射成 Qt 的表格模型界面层用.ui文件描述布局业务层处理工资核算规则。这种分层方式在 Qt 桌面项目里很常见好处是改一个工资项的计算公式不需要动界面代码。2.2 技术栈拆解Qt SQLite 的组合拳这个项目的技术选型很务实没有上重型框架技术组件用途选型理由Qt Widgets界面框架桌面端成熟稳定控件丰富适合表格密集型应用QSqlDatabase SQLite数据存储零配置、单文件、方便随项目分发QTableView QSqlTableModel数据展示模型视图架构数据和界面解耦QDataWidgetMapper表单绑定详情编辑时字段自动同步QPrinter / QTextDocument工资条导出直接生成可打印的工资条我一般会建议初学者从 SQLite 入手因为它不需要你额外装数据库服务.db文件跟着项目走换台机器照样跑。这个项目选 SQLite 而不是 MySQL说明它的定位就是单机或小范围局域网使用不追求高并发追求的是部署简单。2.3 目录结构长什么样解压后典型的目录结构大致是这样Qt_SalaryManager/ ├── Qt_SalaryManager.pro # qmake 工程文件 ├── main.cpp # 程序入口 ├── mainwindow.h/cpp/ui # 主窗口 ├── employee/ # 员工管理模块 │ ├── employeedialog.h/cpp/ui │ └── employeemodel.h/cpp ├── salary/ # 工资核算模块 │ ├── salarycalc.h/cpp │ └── salaryitem.h/cpp ├── attendance/ # 考勤模块 │ └── attendancemodel.h/cpp ├── database/ # 数据库连接与初始化 │ ├── dbmanager.h/cpp │ └── init.sql └── resources/ # 图标、样式、导出模板 └── style.qss这个结构的好处是模块边界清楚。你要改工资计算规则只进salary/目录要加一个员工字段改employee/和init.sql就行。常见做法是把数据库初始化脚本单独放一个init.sql程序首次启动时检测表是否存在不存在就执行建表语句。3. 核心模块拆解从数据库连接到工资核算的完整链路3.1 数据库连接与初始化整个系统的地基是数据库连接。这个项目用QSqlDatabase管理 SQLite 连接通常在dbmanager.cpp里封装成单例或静态方法// dbmanager.cpp bool DbManager::initDatabase() { QSqlDatabase db QSqlDatabase::addDatabase(QSQLITE); // 数据库文件放在程序运行目录下 QString dbPath QCoreApplication::applicationDirPath() /salary.db; db.setDatabaseName(dbPath); if (!db.open()) { qDebug() 数据库打开失败: db.lastError().text(); return false; } // 检查核心表是否存在不存在则建表 QSqlQuery query; if (!query.exec(SELECT name FROM sqlite_master WHERE typetable AND nameemployee)) { qDebug() 查询表失败: query.lastError().text(); return false; } if (!query.next()) { createTables(); // 首次运行执行建表脚本 } return true; }这段代码的关键点有三个第一数据库文件路径用applicationDirPath()而不是硬编码保证换机器能跑第二addDatabase之后必须open()并检查返回值SQLite 打开失败通常是路径没写权限第三建表逻辑用sqlite_master查询判断比CREATE TABLE IF NOT EXISTS更可控因为你可以根据版本做迁移。参数说明QSQLITE是 Qt 自带的 SQLite 驱动不需要额外安装salary.db是数据库文件名你可以改成任何名字但要保证程序对该目录有写权限。3.2 员工信息管理QSqlTableModel 的增删改查员工管理模块是整个系统的数据源头。这个项目用QSqlTableModel直接绑定QTableView省去了手写 Model 的麻烦// employeemodel.cpp void EmployeeModel::setupModel() { model new QSqlTableModel(this); model-setTable(employee); model-setEditStrategy(QSqlTableModel::OnManualSubmit); // 手动提交避免误改 model-select(); // 设置表头显示中文 model-setHeaderData(0, Qt::Horizontal, 工号); model-setHeaderData(1, Qt::Horizontal, 姓名); model-setHeaderData(2, Qt::Horizontal, 部门); model-setHeaderData(3, Qt::Horizontal, 基本工资); model-setHeaderData(4, Qt::Horizontal, 入职日期); ui-tableView-setModel(model); ui-tableView-setSelectionBehavior(QAbstractItemView::SelectRows); ui-tableView-setEditTriggers(QAbstractItemView::NoEditTriggers); // 表格只读编辑走弹窗 }这里有个血泪经验setEditStrategy一定要设成OnManualSubmit。默认的OnFieldChange会在你改完一个单元格、焦点移开时立刻写库用户误触一下就把数据改了没有后悔药。设成手动提交后界面上有“保存”和“撤销”按钮用户确认后再model-submitAll()。参数说明setTable(employee)对应数据库里的员工表setHeaderData的索引要和SELECT语句的字段顺序一致NoEditTriggers让表格只读双击行弹出编辑对话框这样能加校验逻辑。3.3 工资核算引擎把规则从代码里抽出来工资核算是这个项目的核心。如果直接把公式写死在代码里每改一次社保比例就要重新编译这显然不合理。这个项目的做法是把工资项和计算公式存到数据库的salary_item表里-- init.sql 中的工资项配置表 CREATE TABLE salary_item ( id INTEGER PRIMARY KEY AUTOINCREMENT, item_name TEXT NOT NULL, -- 工资项名称如基本工资 item_type INTEGER NOT NULL, -- 0固定项 1考勤扣款 2绩效 formula TEXT, -- 计算公式如base * 0.8 sort_order INTEGER DEFAULT 0 -- 显示顺序 );核算时遍历工资项根据item_type决定取值方式// salarycalc.cpp double SalaryCalc::calcItem(const SalaryItem item, const Employee emp, const Attendance att) { switch (item.type) { case 0: // 固定项直接取员工档案里的值 return emp.baseSalary; case 1: // 考勤扣款按缺勤天数扣 return emp.baseSalary / 21.75 * att.absentDays; case 2: // 绩效按系数乘基本工资 return emp.baseSalary * emp.performanceRate; default: return 0.0; } }这种设计的灵活性在于新增一个工资项只需要在salary_item表里插一条记录不用改代码。常见做法是再配一个公式解析器支持简单的四则运算表达式但那个复杂度会高不少这个项目用switch已经够用。参数说明21.75是月计薪天数这是工资核算里的常见常量absentDays从考勤表按月汇总得到performanceRate存在员工档案里每月可调。3.4 工资条导出QTextDocument 生成可打印文档算完工资要能导出这个项目用QTextDocument拼 HTML 再输出// salaryexport.cpp void SalaryExport::exportToPdf(const QListSalaryRecord records, const QString filePath) { QTextDocument doc; QString html h2工资条/h2table border1 cellspacing0 cellpadding4; html trth工号/thth姓名/thth应发/thth扣款/thth实发/th/tr; for (const auto rec : records) { html QString(trtd%1/tdtd%2/tdtd%3/tdtd%4/tdtd%5/td/tr) .arg(rec.empNo).arg(rec.name) .arg(rec.grossPay, 0, f, 2) .arg(rec.deduction, 0, f, 2) .arg(rec.netPay, 0, f, 2); } html /table; doc.setHtml(html); QPrinter printer(QPrinter::HighResolution); printer.setOutputFormat(QPrinter::PdfFormat); printer.setOutputFileName(filePath); doc.print(printer); }用 HTML 拼表格的好处是排版快QTextDocument对基础 HTML 支持很好。注意金额格式化用arg(value, 0, f, 2)保留两位小数不然会出现3500.0000001这种玄学数字。参数说明QPrinter::HighResolution保证打印清晰度PdfFormat输出 PDF改成NativeFormat可以直接调系统打印机。4. 编译运行避坑从 .pro 到可执行文件的常见问题4.1 环境准备与 .pro 文件配置这个项目用 qmake 构建.pro文件里通常长这样QT core gui sql printsupport greaterThan(QT_MAJOR_VERSION, 4): QT widgets TARGET SalaryManager TEMPLATE app SOURCES main.cpp mainwindow.cpp ... HEADERS mainwindow.h ... FORMS mainwindow.ui ... # 资源文件 RESOURCES resources.qrc关键点是QT sql和QT printsupport。很多人编译报错QSqlDatabase: No such file就是因为忘了加sql模块。printsupport是导出 PDF 用的Qt5 之后打印功能从gui拆出来了不加会报QPrinter找不到。4.2 编译报错排查清单现象一cannot find -lQt5Sql原因Qt 安装时没勾选 SQL 模块或者编译器找不到库路径。 解决用 Qt Maintenance Tool 补装 Qt Sql 模块或者在.pro里确认QT sql已加。现象二程序启动后界面空白数据库没数据原因salary.db文件没生成或者建表脚本没执行。 解决检查applicationDirPath()目录下有没有salary.db没有的话看initDatabase()的返回值在createTables()里加日志。现象三中文显示乱码原因源文件编码和 Qt 运行时编码不一致。 解决在main.cpp里加QTextCodec::setCodecForLocale(QTextCodec::codecForName(UTF-8))Qt5 之后默认 UTF-8但 Windows 下 MSVC 编译器可能需要加/utf-8编译选项。现象四表格里金额显示成科学计数法原因QTableView默认按字符串显示大数字会变1.2e04。 解决自定义QStyledItemDelegate在displayText里用QString::number(value, f, 2)格式化。现象五导出 PDF 时程序崩溃原因QPrinter在无打印机的环境下初始化失败。 解决确保QT printsupport并且QPrinter对象在栈上创建不要用裸指针。提示第一次跑这个项目建议先用 Qt Creator 打开.pro文件选好 Kit桌面版直接点构建。如果报错优先看“编译输出”窗口的第一条错误后面的往往是连锁反应。5. 二次开发改造从能跑到好用要动哪些地方5.1 加一个工资项要改哪几个文件假设你要加一个“交通补贴”固定每月 300 元。改动路径很清晰第一步在salary_item表插一条记录INSERT INTO salary_item (item_name, item_type, formula, sort_order) VALUES (交通补贴, 0, 300, 5);第二步如果item_type0的固定项在代码里是直接取emp.baseSalary你需要把固定项的取值逻辑改成从formula字段解析。常见做法是加一个QVariantMap存员工档案的字段然后用QJSEngine执行公式字符串// 用 QJSEngine 解析公式支持 base * 0.8 300 这种表达式 QJSEngine engine; engine.globalObject().setProperty(base, emp.baseSalary); engine.globalObject().setProperty(absent, att.absentDays); QJSValue result engine.evaluate(item.formula); return result.toNumber();这样改完之后工资项就完全配置化了财务自己就能在界面上加项不用找你改代码。5.2 把 SQLite 换成 MySQL 要动哪里如果团队规模上来了SQLite 的单文件锁扛不住多人同时写换 MySQL 是自然选择。改动集中在DbManager// 原来 QSqlDatabase db QSqlDatabase::addDatabase(QSQLITE); db.setDatabaseName(salary.db); // 换成 QSqlDatabase db QSqlDatabase::addDatabase(QMYSQL); db.setHostName(127.0.0.1); db.setPort(3306); db.setDatabaseName(salary_db); db.setUserName(root); db.setPassword(your_password);然后.pro里QT sql不变但部署时要带上libmysql.dllWindows或确保系统有 MySQL 客户端库。SQL 语句基本不用改因为 Qt 的QSqlQuery屏蔽了大部分方言差异但AUTOINCREMENT要改成AUTO_INCREMENT日期函数也要调整。5.3 一个我踩过的坑事务没提交导致数据丢失早期我在改这个项目时批量导入员工数据用了QSqlTableModel插了 200 条记录后界面显示正常但重启程序数据全没了。排查了半天才发现OnManualSubmit模式下insertRow之后必须调submitAll()否则数据只在内存里。更隐蔽的是如果中途有一条记录违反唯一约束submitAll()会返回 false但前面已经提交的记录不会回滚除非你显式用QSqlDatabase::transaction()包起来。从那以后我每次做批量写库都强制走一遍“开事务 → 批量操作 → 提交 → 检查返回值 → 失败回滚”的流程再也不敢依赖 Model 的自动提交。希望这个习惯也能帮到你。本文还有配套的精品资源点击获取