简介:这是一份面向计算机相关专业在校学生、教师及初学者的C++课程设计项目源码,基于Qt框架实现成绩管理系统,适合用作课程设计、毕业设计、作业提交或项目初期立项演示。项目代码经过实际运行测试,功能完整,可直接下载学习,也便于在现有基础上二次修改扩展。压缩包共包含98个文件,整体约187.59MB,涵盖cpp与h源码文件、ui界面设计文件、qrc资源文件、db数据库文件、dll动态库以及vcxproj工程配置等,覆盖登录、注册、学生管理、教师管理等模块,工程结构完整,便于理解Qt桌面应用的开发流程与模块划分。目前已有62人学习下载,适合希望掌握C++与Qt结合开发、积累课程设计经验的读者参考借鉴。下载后建议先阅读README.md说明,资源仅供学习参考,请勿用于商业用途。
1. 从一份能跑起来的 C++ 课程设计说起:成绩管理系统到底能帮你省多少事
如果你正在搜「c++ 课程设计」,大概率不是想从零啃完一本 C++ 教材,而是手头有个 deadline,需要一个能编译、能跑、能改、能讲清楚原理的完整项目。这份基于 Qt 的成绩管理系统,恰好卡在这个需求点上:它不是控制台里几个cout拼出来的玩具,而是带图形界面、带 SQLite 数据库、带登录注册和三类角色管理的桌面应用。源码包里能看到login.cpp、zhuce.cpp、teachermanagement.cpp、studentmanagement.cpp这些按功能拆分的实现文件,还有.ui界面文件、.qrc资源文件、.vcxproj工程文件和gradesystem.db数据库文件。换句话说,它把「课程设计」这四个字里最耗时间的部分——环境配置、界面搭建、数据库连接、增删改查逻辑——都替你趟过一遍了。适合谁?计科、人工智能、通信、自动化这些专业的在校生,或者刚转 C++ 想找个完整项目练手的开发者。下面我不讲空话,直接拆这份资源的结构、编译路径、数据库设计和几个容易翻车的地方。
2. 拆开压缩包先看什么:工程结构与 Qt 模块依赖
2.1 目录里每个文件在干什么
拿到压缩包别急着双击.sln,先把文件按职责分个类,后面排错会快很多。这份工程大致分四层:
| 文件/目录 | 职责 | 备注 |
|---|---|---|
gradesystem.sln/.vcxproj | Visual Studio 解决方案与工程 | 入口,双击它启动 IDE |
main.cpp | 程序入口,初始化 QApplication | 一般不用改 |
login.cpp/.h/.ui | 登录窗口逻辑与界面 | 改密码逻辑看这里 |
zhuce.cpp/.h/.ui | 注册窗口 | 新用户写入数据库 |
teachermanagement.cpp/.h/.ui | 教师端管理界面 | 成绩录入、修改 |
studentmanagement.cpp/.h/.ui | 学生端查询界面 | 成绩查看 |
gradesystem.db | SQLite 数据库文件 | 核心数据都在这里 |
Resource.qrc/resource.h | 资源文件与资源 ID | 图标、样式等 |
Qt5Core.dll/Qt5Gui.dll/Qt5Widgets.dll | Qt5 运行时库 | 缺了会报「找不到 dll」 |
这里有个细节值得注意:工程同时存在gradesystem.qrc和Resource.qrc,还有resource.h和resource1.h。常见做法是其中一个负责 Qt 资源系统(图片、qss),另一个是 Windows 原生资源(图标、版本信息)。如果你编译时提示资源重复定义,先检查这两个.qrc里有没有同名前缀。
2.2 Qt5 模块依赖与.pro思路
虽然这是 VS 工程,但理解 Qt 的模块划分对排错很关键。这个项目用到的核心模块是三个:
Qt5Core:非 GUI 基础类,QString、QFile、QSqlDatabase 都在这里Qt5Gui:图形基础,QIcon、QPixmapQt5Widgets:窗口控件,QMainWindow、QPushButton、QTableView
数据库部分用的是 Qt 自带的QSqlDatabase+QSQLITE驱动,不需要额外装 MySQL 或 SQL Server。这一点对课程设计很友好——SQLite 是文件型数据库,gradesystem.db直接跟着工程走,拷到别的机器上也能用。
如果你习惯用 qmake,等价的项目文件大概长这样:
QT += core gui widgets sql TARGET = gradesystem TEMPLATE = app SOURCES += main.cpp login.cpp zhuce.cpp \ teachermanagement.cpp studentmanagement.cpp HEADERS += login.h zhuce.h \ teachermanagement.h studentmanagement.h FORMS += login.ui zhuce.ui \ teachermanagement.ui studentmanagement.ui RESOURCES += Resource.qrc逻辑说明:QT += sql是数据库模块,漏了这行编译能过但运行时报「QSqlDatabase: QSQLITE driver not loaded」。FORMS里的.ui文件会被 uic 工具转成ui_*.h,所以你在代码里#include "ui_login.h"是正常的。参数上,TARGET决定生成的 exe 名字,改成别的记得同步改资源引用。
2.3 编译前必须确认的三件事
第一,Qt 版本。工程用的是 Qt5,如果你本机装的是 Qt6,QTextCodec、QRegExp这些类可能已经移除,会报一堆未定义。第二,编译器位数。.vcxproj里如果配的是 x64,你的 Qt 也必须是 x64 版本,32 位 Qt 配 64 位工程会链接失败。第三,数据库驱动。Qt5 默认自带 SQLite 驱动,但如果你用的是自己编译的 Qt,可能没编qsqlite.dll,这时候需要重新配置。
提示:第一次打开
.sln后,先在「解决方案配置」里确认是 Debug 还是 Release,再检查「项目属性 → Qt Project Settings」里的 Qt 版本是否和你安装的一致。
3. 让程序真正跑起来:数据库连接、登录流程与角色跳转
3.1 SQLite 数据库的打开与建表
gradesystem.db是现成的,但你要知道代码是怎么连它的,否则换个路径就懵。典型写法:
#include <QSqlDatabase> #include <QSqlQuery> #include <QSqlError> #include <QDebug> bool initDatabase() { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); // 数据库文件放在可执行文件同级目录 db.setDatabaseName("gradesystem.db"); if (!db.open()) { qDebug() << "打开失败:" << db.lastError().text(); return false; } QSqlQuery query; // 用户表:区分教师和学生 query.exec("CREATE TABLE IF NOT EXISTS users (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "username TEXT UNIQUE NOT NULL," "password TEXT NOT NULL," "role INTEGER NOT NULL)"); // role: 0学生 1教师 // 成绩表:关联学生和课程 query.exec("CREATE TABLE IF NOT EXISTS scores (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "student_id TEXT NOT NULL," "course TEXT NOT NULL," "score REAL)"); return true; }逻辑说明:addDatabase("QSQLITE")注册驱动,setDatabaseName指定文件路径。这里用相对路径,意味着 exe 和 db 必须在同一目录,否则打开失败。role字段用整数区分身份,登录后根据它决定跳教师窗口还是学生窗口。参数上,username加了UNIQUE,重复注册会触发约束错误,代码里要捕获并提示「用户名已存在」。
3.2 登录校验与窗口跳转
登录按钮的槽函数是整个流程的枢纽:
void Login::on_loginButton_clicked() { QString user = ui->usernameEdit->text().trimmed(); QString pwd = ui->passwordEdit->text(); if (user.isEmpty() || pwd.isEmpty()) { QMessageBox::warning(this, "提示", "用户名或密码不能为空"); return; } QSqlQuery query; query.prepare("SELECT role FROM users WHERE username=? AND password=?"); query.addBindValue(user); query.addBindValue(pwd); if (query.exec() && query.next()) { int role = query.value(0).toInt(); if (role == 1) { TeacherManagement *w = new TeacherManagement(); w->show(); } else { StudentManagement *w = new StudentManagement(); w->show(); } this->close(); } else { QMessageBox::critical(this, "错误", "用户名或密码不正确"); } }逻辑说明:prepare+addBindValue是防 SQL 注入的标准做法,别用字符串拼接。query.next()返回 true 说明查到了记录。跳转时new出来的窗口没有父对象,记得在窗口关闭时释放,否则反复登录会内存泄漏。参数上,trimmed()去掉用户名首尾空格,避免用户误输入空格导致登录失败。
3.3 教师端成绩录入与学生端查询
教师端核心是往scores表插数据,学生端是按student_id查。教师端录入:
void TeacherManagement::on_addScore_clicked() { QString sid = ui->studentIdEdit->text(); QString course = ui->courseEdit->text(); double score = ui->scoreSpin->value(); QSqlQuery query; query.prepare("INSERT INTO scores (student_id, course, score) VALUES (?,?,?)"); query.addBindValue(sid); query.addBindValue(course); query.addBindValue(score); if (query.exec()) { QMessageBox::information(this, "成功", "成绩录入完成"); refreshTable(); // 刷新 QTableView } else { QMessageBox::warning(this, "失败", query.lastError().text()); } }学生端查询用QSqlQueryModel绑定到QTableView,一行代码就能把结果集显示出来:
void StudentManagement::loadScores(const QString &sid) { QSqlQueryModel *model = new QSqlQueryModel(this); QSqlQuery query; query.prepare("SELECT course, score FROM scores WHERE student_id=?"); query.addBindValue(sid); query.exec(); model->setQuery(query); model->setHeaderData(0, Qt::Horizontal, "课程"); model->setHeaderData(1, Qt::Horizontal, "成绩"); ui->tableView->setModel(model); }逻辑说明:QSqlQueryModel是只读模型,适合查询展示;如果要可编辑表格,得用QSqlTableModel。参数上,setHeaderData改的是显示表头,不影响数据库字段名。
4. 避坑与排查:编译报错、乱码、数据库锁定这些事
4.1 现象:编译通过但运行提示缺少 Qt5Core.dll
原因:Qt 的 dll 没在系统 PATH 里,或者没把 dll 拷到 exe 同级目录。解决:把 Qt 安装目录下bin里的Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll、Qt5Sql.dll以及platforms/qwindows.dll一起拷过去。注意platforms文件夹要整体拷,只拷 dll 不够。
4.2 现象:中文显示成乱码
原因:源码文件编码和 Qt 运行时编码不一致。VS 默认可能是 GBK,而 Qt5 默认按 UTF-8 处理。解决:在main.cpp里加编码设置,或者把源文件统一存成 UTF-8 with BOM。更稳的做法是用QStringLiteral包中文,或者#pragma execution_character_set("utf-8")。
4.3 现象:数据库被锁定,写入失败
原因:多个窗口同时持有同一个QSqlDatabase连接,或者上一个QSqlQuery没释放。解决:确保QSqlDatabase::addDatabase只调用一次,用QSqlDatabase::database()获取已有连接。查询完及时query.finish()或让 query 对象离开作用域。
4.4 现象:注册新用户提示 UNIQUE 约束失败
原因:username字段设了唯一约束,重复注册同名用户。解决:注册前先SELECT COUNT(*) FROM users WHERE username=?,查到就提示「用户名已存在」,别直接 INSERT 等数据库报错。
4.5 现象:换台电脑后.ui文件打不开或界面错乱
原因:.ui文件是 XML,如果被其他编辑器改过编码或结构,uic 解析会失败。解决:用 Qt Designer 打开确认,别用记事本手改。如果界面控件丢失,检查.ui里的class名和代码里ui->xxx是否对得上。
注意:
.vs文件夹和x64文件夹是 VS 生成的中间产物,换机器时可以删掉重新生成,不影响源码。
5. 进阶改法:把这份课设变成你自己的项目
5.1 加一个「修改密码」功能
现有代码只有登录和注册,改密码需要新增一个对话框。思路是:登录后拿到当前用户名,弹出输入旧密码和新密码,校验旧密码通过后UPDATE users SET password=? WHERE username=?。关键代码:
bool changePassword(const QString &user, const QString &oldPwd, const QString &newPwd) { QSqlQuery query; query.prepare("SELECT id FROM users WHERE username=? AND password=?"); query.addBindValue(user); query.addBindValue(oldPwd); if (!query.exec() || !query.next()) { return false; // 旧密码不对 } QSqlQuery update; update.prepare("UPDATE users SET password=? WHERE username=?"); update.addBindValue(newPwd); update.addBindValue(user); return update.exec(); }参数说明:先查后改,避免直接 UPDATE 导致旧密码错误也执行成功。query.next()确认旧密码匹配后才走更新。
5.2 用 QSS 换一套界面皮肤
Qt 支持类似 CSS 的样式表,在main.cpp里加载一个.qss文件就能全局换肤:
QFile qss(":/style/app.qss"); if (qss.open(QFile::ReadOnly)) { qApp->setStyleSheet(qss.readAll()); qss.close(); }把app.qss加进.qrc资源文件,路径写:/style/app.qss。常见做法是给QPushButton设圆角和渐变,给QTableView设隔行变色。这一步能让课设的观感直接上一个档次,答辩时也好看。
5.3 导出成绩到 Excel 或 CSV
课程设计里经常要求「能导出」。最轻量的方案是写 CSV,不需要额外库:
void exportToCsv(const QString &filename, QSqlQueryModel *model) { QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; QTextStream out(&file); out << "课程,成绩\n"; for (int row = 0; row < model->rowCount(); ++row) { out << model->record(row).value(0).toString() << "," << model->record(row).value(1).toString() << "\n"; } file.close(); }逻辑说明:QTextStream自动处理换行和编码,model->record(row)按行取数据。参数上,文件名建议带时间戳避免覆盖。如果要真正的.xlsx,得引入 QXlsx 这类第三方库,课程设计用 CSV 足够了。
5.4 验证改动的三个习惯
改完代码别急着交,我一般会走一遍:第一,删掉gradesystem.db重新运行,确认建表逻辑能自动重建;第二,用错误密码登录三次,确认不会崩溃;第三,教师端录入一条成绩,切到学生端查同一个学号,确认数据一致。这三步能覆盖大部分逻辑漏洞。从那以后我每次改完数据库相关的代码,都强制走一遍「删库重跑」流程,比事后 debug 省心得多。希望这份拆解帮到你,需要的话直接拿压缩包里的工程对照着改就行。
本文还有配套的精品资源,点击获取