☰
QT+MySQL机房预约系统课设:从环境搭建到避坑指南
2026/10/13 4:43:23 网站建设 项目流程

简介:这份资源是面向高校计算机相关专业学生的课程设计大作业完整项目——机房预约系统,采用C++与QT框架开发,后端接入MySQL数据库,适合正在准备毕业设计、C语言或C++课程设计的学习者参考与二次开发。项目难度适中,源码均经本地编译验证可运行,按文档配置好环境即可启动,能帮助读者快速理解桌面端管理系统的整体架构与实现思路。压缩包共47个文件,约2.8MB,以h头文件与cpp源文件为核心,配合ui界面文件、pro工程配置、Makefile构建脚本及README说明文档,覆盖登录、学生、教师、管理员等多角色模块,目录结构清晰,便于按功能模块检索学习。目前已有75人学习下载。读者可从中获取完整的项目源码、数据库连接与界面交互实现方案,以及可复用的QT工程组织方式,为课程设计答辩与后续开发提供扎实参考。

1. 机房预约系统拆包:一份能跑起来的 QT+MySQL 课设长什么样

课程设计最怕的不是题目难,而是拿到一份源码,编译报错、数据库连不上、界面打不开,最后连答辩都撑不过去。这份「机房预约系统+QT+MySQL」的压缩包,解压后能看到 orderRoomSystem-master 目录,里面是完整的 QT 工程文件:ordersystem.pro、main.cpp、login.cpp、student.cpp、teacher.cpp、manager.cpp,配套的 .ui 界面文件和 .h 头文件一应俱全,还有 Makefile、Makefile.Debug、Makefile.Release 和 object_script 文件,说明它在本地至少完整编译过一轮。数据库层用 connection.h 统一管理连接,业务层按角色拆成学生、教师、管理员三套逻辑,登录入口在 login.cpp,主窗口按权限分流。适合正在做 C++ 课程设计、毕业设计,或者想找一个带完整 UI 和数据库交互的 QT 练手项目的人。它解决的核心问题是:给你一个结构清晰、角色分明、能直接跑通的预约系统骨架,而不是一堆散装代码。

2. 环境搭建与工程加载:从 .pro 到第一个可运行窗口

2.1 QT 版本与编译器选型

这份工程用的是 qmake 构建体系,.pro 文件里没有引入 CMake,所以 QT Creator 打开就能识别。从 Makefile 的命名和 object_script 的路径来看,它大概率是在 Windows 下用 MSVC 或者 MinGW 编译的。我一般会先确认两件事:QT 版本和编译器套件是否匹配。

如果你装的是 QT 5.15.2 + MSVC2019 64bit,直接打开 ordersystem.pro 基本不会有大问题。但如果你用的是 QT 6.x,要注意几个点:QRegExp 在 QT 6 里被移到了兼容模块,QTextCodec 也变了位置,如果源码里用了这些,编译会报错。稳妥的做法是装一个 QT 5.15.x 的长期支持版本,和工程年代对齐。

MySQL 驱动是另一个关键。QT 默认不带 MySQL 驱动,你需要确认 QT 安装目录下的 plugins/sqldrivers 里有没有 qsqlmysql.dll。如果没有,就得自己编译驱动,或者直接用已经编译好的版本。常见做法是:先确认 MySQL 的版本,然后找对应版本的驱动文件放进 sqldrivers 目录。

提示:QT 5.15.2 的离线安装包在 QT 官网归档里还能找到,安装时记得勾选 Sources 和对应的编译器套件,不然后面编译驱动会缺头文件。

2.2 数据库建库与连接配置

工程里 connection.h 是数据库连接的核心文件。打开它,你会看到类似 QSqlDatabase::addDatabase("QMYSQL") 的调用,后面跟着 setHostName、setDatabaseName、setUserName、setPassword 这些配置。你需要根据自己本地的 MySQL 环境改这几个参数。

先建库。打开 MySQL 命令行或者 Navicat,执行:

CREATE DATABASE order_room DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

然后建表。工程里没有附带 .sql 建表文件,这是这份资源的一个小坑。你需要根据代码里的 SQL 语句反推表结构。我一般会先搜代码里所有QSqlQuery的exec调用,把 CREATE TABLE 或者 INSERT 语句找出来。常见的表有这么几张:

表名用途关键字段
user统一用户表id, username, password, role
room机房信息room_id, room_name, capacity, status
order_info预约记录order_id, user_id, room_id, order_date, time_slot, status
notice公告notice_id, content, publish_time

字段类型根据代码里的绑定值来定。比如bindValue(":username", username)传的是 QString,数据库里就用 VARCHAR。日期用 DATE 或 DATETIME,状态用 INT 或 VARCHAR 都行,看代码里怎么比较的。

改完 connection.h 之后,编译运行。如果登录窗口能弹出来,说明数据库连接通了。如果弹不出来,或者点了登录没反应,先看 QT Creator 的 Application Output 里有没有QSqlError的报错信息。

// connection.h 里典型的连接代码 QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("127.0.0.1"); // 本机就写 localhost 或 127.0.0.1 db.setPort(3306); // MySQL 默认端口 db.setDatabaseName("order_room"); db.setUserName("root"); db.setPassword("your_password"); // 改成你自己的密码 if (!db.open()) { qDebug() << "连接失败:" << db.lastError().text(); }

这段代码的逻辑很直白:注册 QMYSQL 驱动,设置连接参数,尝试打开。lastError().text()是排错的关键,它会告诉你到底是驱动没加载、密码错了、还是库不存在。参数方面,setHostName如果 MySQL 和 QT 在同一台机器上,写127.0.0.1比写localhost更稳,因为localhost在某些配置下会走 socket 而不是 TCP。

2.3 编译报错的高频位置

第一次编译,大概率会碰到几类错误。一类是cannot find -lqsqlmysql,说明驱动没配好。另一类是dependent '..\..\..\..\..\..\qt\5.15.2\msvc2019_64\include\qtwid' does not exist,这种路径报错通常是因为 .pro 文件里写了绝对路径,或者 .qmake.stash 缓存了旧路径。解决办法是删掉 .qmake.stash 和 Makefile,重新执行 qmake。

还有一类是中文乱码。QT 5 默认用 UTF-8,但 MSVC 编译器有时候会把源码当成 GBK。在 .pro 里加一行:

QMAKE_CXXFLAGS += /utf-8

这行只对 MSVC 有效。如果你用 MinGW,一般不需要加,但可以在 main.cpp 里设置QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"))来统一编码。

3. 角色权限与预约逻辑:三套 UI 背后的数据流

3.1 登录分流与角色判定

login.cpp 是整个系统的入口。它做的事情不复杂:拿用户输入的账号密码,去 user 表里查,查到之后根据 role 字段决定跳转到哪个窗口。学生进 student.ui,教师进 teacher.ui,管理员进 manager.ui。

代码结构大概是这样的:

// login.cpp 里的登录校验逻辑 QSqlQuery query; query.prepare("SELECT id, role FROM user WHERE username = :user AND password = :pwd"); query.bindValue(":user", ui->lineEdit_user->text()); query.bindValue(":pwd", ui->lineEdit_pwd->text()); if (query.exec() && query.next()) { int role = query.value("role").toInt(); int uid = query.value("id").toInt(); if (role == 0) { StudentWindow *w = new StudentWindow(uid); w->show(); } else if (role == 1) { TeacherWindow *w = new TeacherWindow(uid); w->show(); } else { ManagerWindow *w = new ManagerWindow(); w->show(); } this->close(); } else { QMessageBox::warning(this, "登录失败", "账号或密码错误"); }

prepare+bindValue是防 SQL 注入的标准写法,比直接拼字符串安全。query.next()判断有没有查到记录,查到就取 role 和 id。id 传给子窗口,子窗口后续查预约记录、查个人信息都要用这个 id 做过滤条件。role 的取值 0、1、2 分别对应学生、教师、管理员,这个映射关系在代码里是硬编码的,改的时候要三处一起改。

3.2 学生端预约流程与时间冲突检测

学生端的核心功能是查机房、选时间段、提交预约。student.cpp 里会有查询可用机房的逻辑,一般是查 room 表里 status 为可用的记录,然后按容量或者位置排序。

预约提交的时候,最关键的是冲突检测。同一个机房、同一个时间段,不能有两条有效预约。代码里通常会先查 order_info 表:

// 预约冲突检测 QSqlQuery check; check.prepare("SELECT COUNT(*) FROM order_info " "WHERE room_id = :rid AND order_date = :date " "AND time_slot = :slot AND status = 1"); check.bindValue(":rid", roomId); check.bindValue(":date", date.toString("yyyy-MM-dd")); check.bindValue(":slot", timeSlot); check.exec(); check.next(); if (check.value(0).toInt() > 0) { QMessageBox::information(this, "提示", "该时间段已被预约"); return; }

status = 1表示预约有效,取消的预约 status 改成 0,这样历史记录还在,但不会影响冲突判断。time_slot字段存的是时间段编号,比如 1 表示上午、2 表示下午、3 表示晚上,具体怎么分看代码里的定义。日期用yyyy-MM-dd格式存成字符串或者 DATE 类型都行,但比较的时候格式要一致。

注意:如果数据库里 order_date 存的是 DATETIME,而代码里传的是 DATE 字符串,MySQL 会自动转换,但索引可能失效。数据量大的时候建议统一用 DATE 类型。

3.3 教师端与管理员端的差异

教师端的权限比学生多一层:可以查看自己名下所有学生的预约情况,也可以替学生代预约。teacher.cpp 里会有按教师 id 查关联学生的逻辑,通常是通过班级或者课程表来关联。如果工程里没有班级表,那教师端可能只是简单地查看全部预约记录,然后按教师自己的课程做筛选。

管理员端的 manager.cpp 功能最全:增删改查机房、审核预约、发布公告、管理用户。manager.ui 里的控件也最多,表格、按钮、输入框一大堆。管理员的预约审核逻辑一般是把 order_info 的 status 从待审核改成已通过或者已拒绝。如果代码里没有审核状态字段,那预约就是提交即生效,管理员只能做删除操作。

三套 UI 的 .ui 文件都是 QT Designer 生成的 XML,用 QT Creator 打开就能可视化编辑。如果你想改界面布局,直接双击 .ui 文件拖控件就行,改完保存,重新编译,ui_.h 会自动更新。但要注意,如果你手动改了 ui_.h,重新编译时会被覆盖,所以所有界面改动都应该在 .ui 文件里做。

4. 避坑与排查:编译、连接、乱码、崩溃的常见问题

4.1 驱动加载失败:QMYSQL driver not loaded

现象:程序启动后,数据库连接返回 false,Application Output 里打印QSqlDatabase: QMYSQL driver not loaded。

原因:QT 的 sqldrivers 目录下没有 qsqlmysql.dll,或者 dll 的位数和 QT 套件不匹配(32 位 vs 64 位),或者 MySQL 的 libmysql.dll 不在 PATH 里。

解决:先确认 QT 安装目录下plugins/sqldrivers里有没有 qsqlmysql.dll。如果没有,去 QT 安装目录的Sources/qtbase/src/plugins/sqldrivers/mysql下编译,或者直接下载对应版本的预编译驱动。然后把 MySQL 安装目录下的 libmysql.dll 复制到 QT 的 bin 目录或者工程输出目录。最后在代码里加qDebug() << QSqlDatabase::drivers();看看 QMYSQL 在不在列表里。

4.2 中文乱码:界面显示问号或方块

现象:界面上的中文标签、按钮文字显示成问号或者方块。

原因:源码文件编码、编译器编码、QT 运行时编码三者不一致。MSVC 默认用 GBK 读源码,而 QT 5 默认用 UTF-8 处理字符串。

解决:在 .pro 里加QMAKE_CXXFLAGS += /utf-8,强制 MSVC 用 UTF-8 读源码。如果还有问题,在 main.cpp 里加QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"))。另外检查 .ui 文件里的中文是不是 UTF-8 编码,用 Notepad++ 或者 VS Code 转一下编码。

4.3 编译报错:dependent '............\qt\5.15.2\msvc2019_64\include\qtwid' does not exist

现象:qmake 或者编译的时候报路径不存在,路径里有一长串..。

原因:.qmake.stash 或者 Makefile 里缓存了旧的 QT 安装路径,你换了 QT 版本或者挪了工程目录之后,缓存没清。

解决:删掉工程目录下的 .qmake.stash、Makefile、Makefile.Debug、Makefile.Release,然后在 QT Creator 里执行「构建」→「执行 qmake」,再重新编译。如果还不行,检查 .pro 文件里有没有写死的 INCLUDEPATH 或者 LIBS 路径,改成相对路径或者用$$[QT_INSTALL_HEADERS]这种变量。

4.4 程序崩溃:点击按钮后闪退

现象:登录成功,但点击某个功能按钮后程序直接退出,没有报错弹窗。

原因:空指针访问、数组越界、或者数据库查询返回空结果时没有做判空。

解决:在 QT Creator 里用 Debug 模式运行,崩溃时看调用栈。常见的位置是query.value(0)在query.next()返回 false 的时候被调用,或者ui->tableWidget->item(row, col)在 item 为空的时候被访问。给所有query.next()加判断,给所有item()加判空,能解决大部分闪退。

4.5 预约时间冲突没拦住:同一时段出现两条记录

现象:两个学生同时预约同一个机房的同一时段,系统都提示成功。

原因:冲突检测和插入之间有时间窗口,并发情况下两个请求都通过了检测。

解决:在 order_info 表的(room_id, order_date, time_slot, status)上建唯一索引,或者在插入的时候用INSERT ... SELECT ... WHERE NOT EXISTS的写法。课设级别一般不会真的并发,但如果你要演示给老师看,加个唯一索引更稳妥。

ALTER TABLE order_info ADD UNIQUE KEY uk_room_time (room_id, order_date, time_slot, status);

5. 从能跑到好用:几个让课设加分的小改动

5.1 给预约表加一个状态字段和审核流程

原工程如果只是提交即生效,你可以加一个 status 字段:0 表示待审核,1 表示已通过,2 表示已拒绝。管理员端加一个审核按钮,教师端加一个查看待审核列表的功能。这样整个系统就从「增删改查」升级成了「带工作流的业务系统」,答辩的时候有的讲。

改动点集中在三处:order_info 表加字段、学生端提交时默认 status=0、管理员端加审核按钮和对应的 UPDATE 语句。代码量不大,但业务完整度提升明显。

5.2 用 QSS 统一界面风格

QT 默认的界面控件风格比较朴素。你可以在 main.cpp 里加载一个 .qss 文件,统一按钮、表格、输入框的样式。比如:

QPushButton { background-color: #4a90d9; color: white; border-radius: 4px; padding: 6px 16px; } QLineEdit { border: 1px solid #ccc; border-radius: 4px; padding: 4px; }

把这段存成 style.qss,在 main.cpp 里用QFile读进来,qApp->setStyleSheet(content)。界面立刻从「课设风」变成「产品风」,老师一看就觉得你花了心思。

5.3 加一个日志模块,方便排查问题

工程里有一个 orderInfo.log 文件,说明原作者已经有日志意识了。你可以把它扩展成一个简单的日志类,在关键操作处写日志:登录、预约、取消、审核。日志格式带上时间戳和用户 id,出问题的时候直接看日志文件,比在代码里到处加 qDebug 高效得多。

void writeLog(const QString &action, int userId) { QFile file("orderInfo.log"); if (file.open(QIODevice::Append | QIODevice::Text)) { QTextStream out(&file); out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << " | user:" << userId << " | " << action << "\n"; file.close(); } }

这个函数放在 global.cpp 里,哪里需要就调一下。参数 action 写具体操作,userId 写当前登录用户的 id。日志文件会越来越大,课设级别不用管滚动切割,但你可以加一个按日期分文件的小逻辑,显得更专业。

5.4 数据库连接用单例,别每次操作都新建

connection.h 如果每次查询都addDatabase,会重复注册连接,QT 会警告duplicate connection name。正确的做法是用单例模式,全局只初始化一次,后面所有查询复用同一个QSqlDatabase对象。改法很简单:把连接逻辑放到一个静态函数里,第一次调用时初始化,后面直接返回已有的连接。

QSqlDatabase& getDb() { static QSqlDatabase db; if (!db.isValid()) { db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("127.0.0.1"); // ... 其他配置 db.open(); } return db; }

这样改完,连接只建一次,查询效率更高,也不会再报重复连接的警告。参数方面,static保证了只初始化一次,isValid()判断是否已经配置过。如果你需要多线程访问数据库,每个线程要单独建连接,那就不能用这个单例,得改成按线程存储。

5.5 打包发布:让没装 QT 的电脑也能跑

课设答辩的时候,老师的电脑不一定有 QT 环境。你需要用windeployqt工具把依赖的 dll 打包到一起。步骤是:先用 Release 模式编译,然后把生成的 exe 复制到一个空文件夹,在 QT 命令行里执行windeployqt your.exe,它会自动把 Qt5Core.dll、Qt5Gui.dll、Qt5Sql.dll、platforms/qwindows.dll 这些复制过来。MySQL 的 libmysql.dll 和 sqldrivers/qsqlmysql.dll 要手动复制。最后把整个文件夹压缩,到任何 Windows 电脑上解压就能跑。

从那以后我每次交付 QT 项目,都会先在干净虚拟机上跑一遍 windeployqt 打包,确认没有缺 dll 再交出去。这个习惯帮我省掉了无数次「在我电脑上好好的」的尴尬。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询