C++课程设计实战:基于QT与SQLite的教室管理系统开发指南

发布时间:2026/7/17 23:07:28

C++课程设计实战:基于QT与SQLite的教室管理系统开发指南 1. 项目概述与核心价值最近在带学生做课程设计发现很多同学对“C课程设计QTSQL教室管理系统”这个题目既兴奋又迷茫。兴奋在于这听起来是一个能写在简历上的“正经”项目迷茫则在于QT和SQL这两个庞然大物加上C本身不知道从哪里下嘴。我自己当年也是从这个阶段过来的深知一个清晰的实战路径有多重要。这个项目绝不仅仅是为了应付作业它本质上是一个微型的企业级桌面应用开发演练涵盖了从需求分析、UI设计、业务逻辑编码、数据库操作到最终打包发布的完整流程。掌握了它你就相当于亲手搭建了一个软件开发的“最小可行产品”MVP模型对理解客户端-服务器架构、数据持久化、事件驱动编程等核心概念有巨大帮助。简单来说这个系统要干的事就是模拟学校教务部门对教室资源的管理。核心用户比如教务员通过一个图形界面QT实现能方便地完成对教室信息的增删改查CRUD、预约教室、查看预约状态等操作而所有这些数据都安全、持久地存储在一个数据库SQL实现里。它麻雀虽小五脏俱全非常适合作为C从语法学习迈向综合应用开发的桥梁。2. 技术栈选型与环境搭建为什么是QTSQL这不是随便选的组合而是经过实践检验的“黄金搭档”。C负责核心业务逻辑性能强劲QT作为跨平台的GUI框架提供了极其丰富的控件和信号槽机制让界面开发变得直观SQL这里通常指SQLite或MySQL则负责数据的结构化存储和高效查询。这个组合能让你在巩固C面向对象思想的同时接触到现代软件工程的实际工具链。2.1 开发环境配置详解工欲善其事必先利其器。一个顺手的开发环境能避免无数坑。1. 编译器与构建工具对于Windows平台首推使用MSVCMicrosoft Visual C编译器套件。最简单的方式是安装Visual Studio 2022 Community版在安装时勾选“使用C的桌面开发”工作负载它会自动安装MSVC、Windows SDK等必备组件。即便你后续主要用其他编辑器这个编译器也是基础。避免使用MinGW除非你有特定跨平台需求因为它在链接某些库时更容易出问题。2. QT框架安装直接去QT官网下载在线安装器qt-unified-windows-x64-online.exe。安装时关键步骤在于组件选择QT版本对于学习和课程设计选择QT 5.15.2 LTS长期支持版是最稳妥的。它足够稳定社区资源丰富。不必追求最新的QT6除非项目有特定需求。编译器务必勾选与你安装的MSVC版本对应的组件例如MSVC 2019 64-bit。这是QT能与你的编译器对话的关键。额外组件勾选Qt Creator官方IDE对新手友好和SourcesQT源码方便调试时查看。Qt Charts、Qt Data Visualization等视项目需要选择教室管理系统一般用不上。3. 数据库选择与配置对于课程设计级别的项目SQLite是完美选择。它无需安装独立的数据库服务器整个数据库就是一个.db或.sqlite文件非常适合嵌入式或单机桌面应用。QT原生就通过QtSql模块提供了对SQLite的完美支持。 如果你想挑战一下也可以安装MySQL或PostgreSQL这能让你接触到客户端-服务器模式的数据库操作但需要额外安装和配置数据库服务复杂度会高一些。我建议初学者先从SQLite入手把核心逻辑跑通。4. 代码编辑器/IDEQt CreatorQT亲儿子开箱即用对QT项目支持最好内置UI设计器、调试器非常适合新手快速上手。配置简单新建项目时选择正确的Kit即编译器QT版本组合即可。Visual Studio功能强大调试体验极佳。需要安装“QT VS Tools”插件才能在VS内管理QT项目和使用UI设计器。适合喜欢VS生态或项目较复杂的同学。VSCode轻量灵活通过安装C、QT、CMake等插件也能配置出强大的环境。但这需要较强的动手能力要自己配置CMakeLists.txt或qmake的构建任务、头文件路径等。不建议课程设计初期折腾容易劝退。实操心得强烈建议课程设计新手直接使用Qt Creator QT 5.15.2 MSVC SQLite这个组合。它把环境配置的复杂度降到了最低让你能把精力集中在编码和逻辑实现上。在Qt Creator中新建项目时务必在“Kit Selection”那一步选择你安装好的那个带有MSVC和QT版本的Kit这是项目能成功编译运行的基石。2.2 项目工程结构设计在动手写代码前花点时间规划一下工程目录好的结构是成功的一半。一个清晰的QT项目目录通常如下ClassroomManager/ ├── ClassroomManager.pro # QMake项目文件如果用CMake则是CMakeLists.txt ├── main.cpp # 程序入口 ├── mainwindow.ui # 主窗口界面文件XML格式由Qt Designer编辑 ├── mainwindow.h # 主窗口头文件 ├── mainwindow.cpp # 主窗口实现文件 ├── database/ │ ├── databaseconnection.h # 数据库连接类声明 │ └── databaseconnection.cpp # 数据库连接类实现 ├── entities/ # 实体类对应数据库表 │ ├── classroom.h/.cpp │ └── reservation.h/.cpp ├── widgets/ # 自定义控件或对话框 │ ├── classroomdialog.h/.cpp │ └── reservationdialog.h/.cpp └── resources/ # 资源文件如图标、图片 └── images/在ClassroomManager.pro文件中你需要添加必要的模块依赖这是很多人会忘记的一步QT core gui sql widgets # 核心、GUI、SQL和控件模块 greaterThan(QT_MAJOR_VERSION, 4): QT widgets # 兼容性语句 TARGET ClassroomManager TEMPLATE app SOURCES ... # 源文件 HEADERS ... # 头文件 FORMS ... # UI文件注意第一行QT sql这是让你的程序能够使用QSqlDatabase等数据库类的关键。3. 数据库设计与核心业务逻辑数据库是整个系统的“记忆中枢”设计的好坏直接决定了程序是否健壮和高效。3.1 数据库表结构规划我们至少需要两张核心表教室表和预约记录表。它们之间通过教室ID进行关联。1. 教室表 (classroom)这张表存储教室的静态信息。字段名数据类型约束说明idINTEGERPRIMARY KEY AUTOINCREMENT主键自增唯一标识一间教室room_numberVARCHAR(20)NOT NULL UNIQUE教室编号如“A101”必须唯一buildingVARCHAR(50)NOT NULL所在楼栋如“逸夫楼”capacityINTEGERNOT NULL CHECK(capacity 0)容纳人数has_multimediaBOOLEANDEFAULT 0是否有多媒体设备0否1是descriptionTEXT备注信息2. 预约记录表 (reservation)这张表记录动态的预约事件。字段名数据类型约束说明idINTEGERPRIMARY KEY AUTOINCREMENT预约记录IDclassroom_idINTEGERNOT NULL外键关联classroom.idapplicantVARCHAR(100)NOT NULL申请人如班级、社团、教师名purposeVARCHAR(200)NOT NULL使用用途start_timeDATETIMENOT NULL预约开始时间end_timeDATETIMENOT NULL预约结束时间statusVARCHAR(20)DEFAULT pending状态pending审核中, approved已通过, rejected已拒绝FOREIGN KEY (classroom_id) REFERENCES classroom(id) ON DELETE CASCADE外键约束删除教室时级联删除其预约设计要点start_time和end_time使用DATETIME类型便于进行时间范围的查询和冲突检测。status字段为工作流预留了空间简单的系统可以只有“已预约”复杂的可以加入审核流程。3.2 数据库连接与初始化封装在QT中操作数据库最佳实践是将其封装成一个单独的类例如DatabaseConnection。这个类负责数据库的连接、关闭、以及执行一些通用的初始化SQL建表。databaseconnection.h 关键部分#ifndef DATABASECONNECTION_H #define DATABASECONNECTION_H #include QSqlDatabase #include QString class DatabaseConnection { public: static DatabaseConnection getInstance(); // 单例模式全局一个连接 bool openConnection(const QString dbPath classroom.db); void closeConnection(); QSqlDatabase getDatabase() const; bool initDatabase(); // 初始化表结构 private: DatabaseConnection() default; // 私有构造函数 QSqlDatabase m_db; }; #endif // DATABASECONNECTION_Hdatabaseconnection.cpp 中的连接与初始化#include databaseconnection.h #include QSqlQuery #include QSqlError #include QDebug #include QFile #include QDir DatabaseConnection DatabaseConnection::getInstance() { static DatabaseConnection instance; return instance; } bool DatabaseConnection::openConnection(const QString dbPath) { // 确保数据库文件所在目录存在 QFileInfo fileInfo(dbPath); QDir dir fileInfo.dir(); if (!dir.exists()) { dir.mkpath(.); } m_db QSqlDatabase::addDatabase(QSQLITE); // 指定SQLite驱动 m_db.setDatabaseName(dbPath); if (!m_db.open()) { qDebug() Failed to open database: m_db.lastError().text(); return false; } qDebug() Database connected successfully.; return true; } bool DatabaseConnection::initDatabase() { QSqlQuery query(m_db); QStringList sqls; // 创建教室表 sqls CREATE TABLE IF NOT EXISTS classroom ( id INTEGER PRIMARY KEY AUTOINCREMENT, room_number VARCHAR(20) NOT NULL UNIQUE, building VARCHAR(50) NOT NULL, capacity INTEGER NOT NULL CHECK(capacity 0), has_multimedia BOOLEAN DEFAULT 0, description TEXT );; // 创建预约表 sqls CREATE TABLE IF NOT EXISTS reservation ( id INTEGER PRIMARY KEY AUTOINCREMENT, classroom_id INTEGER NOT NULL, applicant VARCHAR(100) NOT NULL, purpose VARCHAR(200) NOT NULL, start_time DATETIME NOT NULL, end_time DATETIME NOT NULL, status VARCHAR(20) DEFAULT pending, FOREIGN KEY (classroom_id) REFERENCES classroom(id) ON DELETE CASCADE );; // 为预约表的教室ID和时间字段创建索引大幅提升查询速度 sqls CREATE INDEX IF NOT EXISTS idx_reservation_classroom ON reservation(classroom_id);; sqls CREATE INDEX IF NOT EXISTS idx_reservation_time ON reservation(start_time, end_time);; for (const QString sql : sqls) { if (!query.exec(sql)) { qDebug() Init database failed at SQL: sql; qDebug() Error: query.lastError().text(); return false; } } return true; }避坑指南单例模式桌面应用通常只需要一个全局数据库连接单例模式可以避免重复连接和资源浪费。路径处理数据库文件路径最好使用相对路径或放在用户可写目录如QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)避免因程序安装位置权限问题导致创建文件失败。错误处理每次执行SQL后检查query.lastError()是必须的。将错误信息用qDebug()输出是调试数据库问题时最直接的手段。创建索引reservation表会频繁按classroom_id和start_time/end_time查询例如查某教室某时间段是否被占用。为这些字段创建索引是至关重要的性能优化能让查询速度提升几个数量级数据量越大效果越明显。这是很多新手会忽略的一点。4. QT界面设计与数据绑定QT的强大之处在于其信号槽机制和Model/View架构能让界面和数据逻辑优雅地解耦。4.1 主界面布局与控件选择使用Qt Designer拖拽生成mainwindow.ui。主界面可以设计为常见的“左侧导航树/列表右侧详情与操作”布局。左侧一个QListWidget或QTreeWidget用于展示教室列表。右侧上部一个QTableView用于显示当前选中教室的预约记录。这是展示数据库数据的最佳控件。右侧下部一系列按钮QPushButton如“新增教室”、“删除教室”、“预约教室”、“刷新”等以及一些用于筛选的输入框如QLineEdit用于搜索QDateTimeEdit用于选择日期。关键是要为QTableView设置一个模型Model。我们将使用QSqlTableModel或QSqlQueryModel它们能直接与数据库交互自动处理数据的显示、排序和部分编辑。4.2 使用Model-View架构展示数据在mainwindow.cpp的初始化函数中我们需要建立模型与视图的连接。// mainwindow.cpp 构造函数或初始化函数中 #include mainwindow.h #include ui_mainwindow.h #include databaseconnection.h #include QSqlTableModel #include QSqlQuery #include QMessageBox MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui-setupUi(this); // 1. 初始化数据库 DatabaseConnection db DatabaseConnection::getInstance(); if (!db.openConnection() || !db.initDatabase()) { QMessageBox::critical(this, 错误, 数据库初始化失败); return; } // 2. 创建教室列表的模型 (使用QSqlQueryModel因为可能涉及复杂查询如联表) m_classroomModel new QSqlQueryModel(this); m_classroomModel-setQuery(SELECT id, room_number, building, capacity FROM classroom ORDER BY building, room_number); ui-listViewClassroom-setModel(m_classroomModel); // 假设使用ListView ui-listViewClassroom-setModelColumn(1); // 显示room_number列 // 3. 创建预约记录表格的模型 (使用QSqlTableModel方便过滤和编辑) m_reservationModel new QSqlTableModel(this, db.getDatabase()); m_reservationModel-setTable(reservation); m_reservationModel-setEditStrategy(QSqlTableModel::OnManualSubmit); // 手动提交修改 // 设置表头显示名称 m_reservationModel-setHeaderData(m_reservationModel-fieldIndex(applicant), Qt::Horizontal, tr(申请人)); m_reservationModel-setHeaderData(m_reservationModel-fieldIndex(purpose), Qt::Horizontal, tr(用途)); m_reservationModel-setHeaderData(m_reservationModel-fieldIndex(start_time), Qt::Horizontal, tr(开始时间)); m_reservationModel-setHeaderData(m_reservationModel-fieldIndex(end_time), Qt::Horizontal, tr(结束时间)); m_reservationModel-setHeaderData(m_reservationModel-fieldIndex(status), Qt::Horizontal, tr(状态)); ui-tableViewReservation-setModel(m_reservationModel); ui-tableViewReservation-horizontalHeader()-setStretchLastSection(true); // 最后一列拉伸 // 4. 连接信号槽当选中教室变化时刷新右侧的预约表格 connect(ui-listViewClassroom-selectionModel(), QItemSelectionModel::currentRowChanged, this, MainWindow::onClassroomSelectionChanged); } void MainWindow::onClassroomSelectionChanged(const QModelIndex ¤t, const QModelIndex previous) { Q_UNUSED(previous); if (!current.isValid()) { m_reservationModel-setFilter(); // 清空筛选显示所有或者清空模型 m_reservationModel-select(); return; } // 获取选中教室的ID int classroomId m_classroomModel-data(m_classroomModel-index(current.row(), 0)).toInt(); // 第0列是id // 设置过滤器只显示该教室的预约记录 QString filter QString(classroom_id %1).arg(classroomId); m_reservationModel-setFilter(filter); m_reservationModel-select(); // 重新查询 }核心技巧QSqlTableModel的setEditStrategy非常重要。OnManualSubmit意味着修改不会立即写入数据库需要调用submitAll()。这给了我们做数据校验和撤销操作的机会。OnRowChange或OnFieldChange则是一修改就提交风险较高。数据映射表格直接显示外键classroom_id对用户不友好。更优的做法是重写QSqlTableModel的data()函数或者使用QSqlRelationalTableModel将classroom_id自动替换为room_number显示。这涉及到关系模型是进阶内容但能让用户体验提升一个档次。性能QSqlTableModel在数据量很大比如超过万行时一次性select()可能会卡顿。可以考虑使用QSqlQuery进行分页查询或者使用QTableView的setIndexWidget等进行懒加载优化。对于课程设计规模直接使用通常没问题。4.3 实现增删改查对话框“新增教室”、“预约教室”等功能通常通过弹出对话框QDialog来实现。在Qt Designer中新建对话框.ui文件设计好表单QLineEdit、QSpinBox、QDateTimeEdit、QComboBox等。以新增教室对话框ClassroomDialog为例classroomdialog.cpp 中的提交按钮槽函数void ClassroomDialog::on_buttonBox_accepted() { QString roomNumber ui-lineEditRoomNumber-text().trimmed(); QString building ui-lineEditBuilding-text().trimmed(); int capacity ui-spinBoxCapacity-value(); bool hasMultimedia ui-checkBoxMultimedia-isChecked(); QString description ui-textEditDescription-toPlainText().trimmed(); // 1. 数据校验 if (roomNumber.isEmpty() || building.isEmpty()) { QMessageBox::warning(this, 输入错误, 教室编号和楼栋不能为空); return; } // 检查教室编号是否已存在 QSqlQuery query(DatabaseConnection::getInstance().getDatabase()); query.prepare(SELECT COUNT(*) FROM classroom WHERE room_number ?); query.addBindValue(roomNumber); if (query.exec() query.next() query.value(0).toInt() 0) { QMessageBox::warning(this, 输入错误, 教室编号已存在); return; } // 2. 插入数据库 query.prepare(INSERT INTO classroom (room_number, building, capacity, has_multimedia, description) VALUES (?, ?, ?, ?, ?)); query.addBindValue(roomNumber); query.addBindValue(building); query.addBindValue(capacity); query.addBindValue(hasMultimedia ? 1 : 0); query.addBindValue(description); if (!query.exec()) { QMessageBox::critical(this, 数据库错误, 插入教室信息失败\n query.lastError().text()); return; } // 3. 成功关闭对话框 (accept()会触发accepted()信号) accept(); }注意事项SQL注入防御永远不要用字符串拼接的方式构造SQL语句如QString sql INSERT ... VALUES ( roomNumber )。这极其危险务必使用参数化查询Prepared Statement即上面代码中的?占位符和addBindValue()方法。这是编写数据库程序必须养成的安全习惯。数据校验前端UI的校验如QIntValidator和后台逻辑的校验缺一不可。后台校验是保证数据完整性的最后防线。用户反馈任何数据库操作成功或失败都应通过QMessageBox等方式给用户明确的反馈。5. 核心业务功能实现与难点解析有了基础的CRUD接下来实现系统的核心业务逻辑教室预约与冲突检测。5.1 预约逻辑与时间冲突检测这是整个系统的业务核心。当用户提交一个预约申请申请人、用途、开始时间、结束时间、教室ID时我们必须检查该教室在所选时间段内是否已被占用。reservationdialog.cpp 中的冲突检测函数bool ReservationDialog::checkTimeConflict(int classroomId, const QDateTime startTime, const QDateTime endTime, int excludeReservationId) { // excludeReservationId用于在“修改”预约时排除自身这条记录 if (startTime endTime) { QMessageBox::warning(this, 时间错误, 结束时间必须晚于开始时间); return true; // 视为冲突阻止提交 } QSqlQuery query(DatabaseConnection::getInstance().getDatabase()); QString sql SELECT COUNT(*) FROM reservation WHERE classroom_id ? AND status ! rejected // 通常被拒绝的预约不占资源 AND ((start_time ? AND end_time ?) // 新预约在已有预约中间开始 OR (start_time ? AND end_time ?) // 新预约在已有预约中间结束 OR (start_time ? AND end_time ?)); // 新预约完全在已有预约范围内或反之 if (excludeReservationId ! -1) { sql AND id ! ?; } query.prepare(sql); query.addBindValue(classroomId); query.addBindValue(endTime); query.addBindValue(startTime); query.addBindValue(endTime); query.addBindValue(startTime); query.addBindValue(startTime); query.addBindValue(endTime); if (excludeReservationId ! -1) { query.addBindValue(excludeReservationId); } if (!query.exec()) { qDebug() Conflict check query failed: query.lastError().text(); return true; // 查询失败保守起见视为冲突 } if (query.next()) { return query.value(0).toInt() 0; // 如果找到记录数0说明有冲突 } return false; }在提交预约的槽函数中调用void ReservationDialog::on_buttonBox_accepted() { // ... 获取对话框中的输入数据 classroomId, startTime, endTime 等 ... int reservationId -1; // 新增时为-1修改时传入原有ID if (checkTimeConflict(classroomId, startTime, endTime, reservationId)) { QMessageBox::warning(this, 预约冲突, 该教室在所选时间段内已被占用请选择其他时间或教室。); return; // 阻止提交 } // ... 通过校验执行INSERT或UPDATE操作 ... }难点解析时间冲突检测的SQL条件是关键。上面代码中的条件覆盖了所有重叠情况新预约的开始时间在某个已有预约之内。新预约的结束时间在某个已有预约之内。新预约完全包含了某个已有预约或完全被包含。 用数学区间来表示就是判断两个时间段[start1, end1]和[start2, end2]是否有交集条件是start1 end2 start2 end1。上面的SQL语句是这种逻辑的展开形式并考虑了状态过滤如rejected状态不冲突和排除自身修改时的情况。5.2 数据查询与筛选功能主界面通常需要提供搜索功能例如按楼栋筛选教室或按日期范围查询预约。在MainWindow中实现一个搜索教室的函数void MainWindow::on_searchButton_clicked() { QString buildingFilter ui-comboBoxBuildingFilter-currentText(); // 楼栋筛选 QString roomKeyword ui-lineEditRoomSearch-text().trimmed(); // 教室编号关键字 int minCapacity ui-spinBoxMinCapacity-value(); // 最小容量 QString whereClause 11; // 永真条件便于拼接 if (!buildingFilter.isEmpty() buildingFilter ! 全部) { whereClause QString( AND building %1).arg(buildingFilter); // 注意简单拼接有风险建议用参数化 } if (!roomKeyword.isEmpty()) { whereClause QString( AND room_number LIKE %%1%).arg(roomKeyword); } whereClause QString( AND capacity %1).arg(minCapacity); QString queryStr QString(SELECT id, room_number, building, capacity FROM classroom WHERE %1 ORDER BY building, room_number).arg(whereClause); m_classroomModel-setQuery(queryStr); // 更好的做法是使用参数化查询构建queryStr这里为演示简洁用了拼接实际项目务必用参数化 }安全提醒上面的搜索示例为了直观使用了字符串拼接来构建WHERE子句这在buildingFilter或roomKeyword来自用户输入时是极其危险的会引发SQL注入。在实际编码中必须使用参数化查询来构建动态SQL即使它看起来更复杂一些。可以构建一个带参数的QSqlQuery然后根据条件动态添加AND子句和绑定对应的值。6. 项目调试、打包与部署功能开发完成后让程序能稳定运行并交付给别人使用是最后也是重要的一步。6.1 常见问题与调试技巧数据库连接失败现象程序启动时报错“QSQLITE: Unable to open database”。排查检查数据库文件路径是否正确、是否有写权限。使用qDebug() QDir::currentPath();输出当前工作目录。最好使用绝对路径或位于用户目录下的路径。解决在openConnection函数中先检查目录是否存在不存在则创建。中文乱码现象界面或数据库中的中文显示为问号或乱码。解决源代码文件编码确保.cpp和.h文件保存为UTF-8 with BOM在Windows上Qt Creator默认如此。在Qt Creator中可通过“编辑”-“Select Encoding”查看和转换。数据库编码SQLite默认UTF-8一般没问题。如果从其他来源导入数据注意编码转换。界面显示确保UI文件中的中文也正常。有时需要在main函数开头设置编码QTextCodec::setCodecForLocale(QTextCodec::codecForName(UTF-8));QT5中方式有所变化可查询QTextCodec或QString的相关文档。程序崩溃QT崩溃常见原因空指针访问、信号槽连接错误参数类型不匹配、在错误的线程中操作GUI。调试在Qt Creator中以Debug模式运行当崩溃时查看“应用程序输出”和“调试器”面板的调用堆栈Call Stack能精确定位到出错的代码行。预防对任何可能为空的指针如通过ui-xxx获取未初始化的控件、new失败的对象进行判空。使用Q_DECL_OVERRIDE检查虚函数重写。仔细检查信号槽连接的参数。SQL语句执行错误永远检查QSqlQuery::lastError()。将错误信息打印到控制台或日志文件。使用QSqlQuery::prepare()和addBindValue()避免语法错误和注入。在开发阶段可以先将要执行的SQL字符串打印出来放到数据库管理工具如DB Browser for SQLite里执行看是否有语法错误。6.2 项目打包发布在Qt Creator中使用Release模式编译项目后你会得到一个.exe文件。但这个.exe不能单独运行它依赖一堆QT的动态链接库DLL。使用windeployqt工具自动化打包这是QT官方提供的部署工具能自动找到你的程序所需的所有依赖库。在开始菜单找到“Qt 5.15.2 (MSVC 2019 64-bit)”下的“Qt 5.15.2 (MSVC 2019 64-bit) Command Prompt”打开它。命令行切换到你的Release版.exe文件所在的目录。执行命令windeployqt --release --no-compiler-runtime --no-angle --no-opengl-sw YourAppName.exe--release部署Release版本。--no-compiler-runtime不包含VC运行时库用户可能需要单独安装。--no-angle、--no-opengl-sw排除一些不常用的图形模块减小体积。执行后该目录下会生成许多.dll文件、platforms文件夹等。此时这个目录下的所有文件一起就可以拷贝到其他没有安装QT的Windows电脑上运行了。进一步精简和制作安装包精简检查windeployqt生成的DLL有些可能用不到比如Qt5SerialPort.dll如果没用到串口。可以尝试删除一些然后在干净的虚拟机里测试是否运行正常。安装包使用Inno Setup或NSIS等免费安装包制作工具将你的程序文件夹打包成一个.exe安装程序可以添加桌面快捷方式、开始菜单项等显得更专业。完成以上所有步骤一个功能完整、结构清晰、可以独立运行的“QTSQL教室管理系统”就真正完成了。这个过程里你实践的不只是C语法更是软件工程的全流程。遇到问题、解决问题的过程才是课程设计带给你的最大财富。

相关新闻