很多学了 C++ 的同学都会遇到同一个尴尬:语法、指针、类都能看懂,但让他做一个“能用的软件”时,第一反应是打开命令行,写一个黑窗口程序,最多再加个循环菜单。问题不在于 C++ 没学会,而是从来没有把一个完整项目的链路跑通过:用户怎么操作界面,程序怎么处理数据,数据最终存在哪里,下一次启动怎么再读出来。
Qt6 + MySQL 正是补上这一环的最典型组合。Qt6 是目前 C++ 桌面开发主流的 GUI 框架,MySQL 是使用最广泛的关系型数据库之一,两者结合覆盖了“界面操作 -> 业务逻辑 -> 数据存储 -> 结果回显”的完整开发流程。这篇文章的目的,就是带你把这条链路真正跑通。
先说结论:对 Qt 编程小白来说,第一个实战项目不应该追求界面多炫酷,而应该求“数据能存进去、能查出来、能在界面上增删改查”。把这个闭环做完,你才算真正迈过了从 C++ 语法到桌面应用开发的门槛。
1. 为什么建议把 Qt6 + MySQL 作为小白的第一个实战项目
先说一个很多初学者容易踩的坑:学 Qt 的第一周就去做复杂项目,比如仿一个音乐播放器、做一个聊天软件、写一个带动画的数据大屏。这类项目听起来有吸引力,但开发周期长、依赖多、出了问题也不知道错在哪一层。最后常见的结果是代码写了一千行,真正理解的却很少。
更合理的做法是选一个“麻雀虽小、五脏俱全”的项目。所谓五脏,指的是:
- 有一个用户看得见的 GUI 界面;
- 有按钮点击、输入框获取、表格展示等基础交互;
- 有真实的数据库存储,而不是把数据放在内存里;
- 有查询、新增、修改、验证等业务逻辑;
- 有程序运行失败时能定位问题的排查路径。
Qt6 + MySQL 做登录验证加简单数据管理,刚好能满足以上所有要求。你可以学会 Qt 的信号槽机制,学会 QSqlDatabase 建立数据库连接,学会 QSqlQuery 执行 SQL,学会 QSqlTableModel 把数据库表映射到界面,同时还会遇到驱动加载、编码、发布等真实项目里绕不开的问题。
这个项目还特别适合三类人:第一类是刚学完 C++ 基础、想进入 GUI 开发的初学者;第二类是学校课程设计需要做管理系统的同学;第三类是想转 C++ 桌面开发、希望通过一个小项目建立完整认知的开发者。
当然也要说清楚不适合谁。如果你的目标是后端服务或者 Web 前端开发,那就没必要把 Qt 当主线;如果只是想学 SQL,直接用命令行操作数据库反而更高效。Qt6 + MySQL 的价值在于“图形界面 + 数据库”的组合,这是桌面管理类项目的典型形态。
2. 项目定调:先想清楚它到底在做什么
在动手写代码之前,先把项目拆开看。一个完整的 Qt 桌面数据库程序,通常可以分成三层:
- 表现层:负责和用户交互,包括 QWidget、QDialog、QMainWindow、QTableView 等控件;
- 业务层:负责接收界面传来的数据,做校验、逻辑判断,再调用数据层接口;
- 数据层:负责和 MySQL 通信,执行 INSERT、SELECT、UPDATE、DELETE 等 SQL 语句。
比如登录功能的完整流程是:用户在 QLineEdit 里输入用户名和密码,点击登录按钮后,Qt 发出 clicked 信号,对应的槽函数读取输入框内容,调用一个验证函数。验证函数把用户名和密码作为参数传入 SQL 查询,连接 MySQL,执行 SELECT,然后根据结果决定是跳转到主窗口还是弹出错误对话框。
这个过程涉及 Qt 的几个核心类,建议你一开始就把它们的关系理清楚:
- QSqlDatabase:代表一个数据库连接,可以设置主机名、端口、用户名、密码和数据库名称;
- QSqlQuery:执行一条 SQL 语句,负责增删改查;
- QSqlTableModel:把一张表映射为 Qt 的 Model,配合 QTableView 可以自动显示数据;
- QSqlError:保存数据库操作失败时的错误信息,排查问题时非常重要。
理解了这个结构,你就能明白:写 Qt 数据库程序,本质上就是在“界面控件”和“SQL 语句”之间搭桥。界面负责收集用户输入,SQL 负责把数据持久化到 MySQL,查询结果再通过 Model 更新到界面。这个核心认知,比记住某个 API 更重要。
3. Qt 6 与 MySQL 环境准备
3.1 安装 Qt 6
Qt 的安装建议直接从 Qt 官网使用在线安装器完成。进入 Qt 官网的下载页面后,选择适合自己操作系统的在线安装包,下载后登录 Qt 账号,选择要安装的组件。
这里有一个关键选择:编译套件。Windows 下你会碰到 MSVC 和 MinGW 两种选择。MSVC 使用 Microsoft Visual C++ 编译器,一般需要安装对应版本的 Visual Studio Build Tools;MinGW 是 GCC 在 Windows 下的移植版本,使用起来更轻便。选择二者都可以,但要注意两点:
- 你选的 Qt 套件必须能正常编译,建议在 Qt Creator 里创建一个空项目验证;
- 后续连接 MySQL 时,Qt 套件的位数必须和 MySQL 客户端库的位数一致,64 位配 64 位,32 位配 32 位。
在 Qt 版本的选择上,建议直接选择 Qt 6.x 中带有 LTS 标识的版本。LTS 表示长期支持版本,官方维护周期更长,学习阶段使用更稳妥。
3.2 安装 MySQL 并初始化
MySQL 的安装方式有两种主流选择。第一种是安装 MySQL Community Server,前往 MySQL 官网下载对应系统的安装包,安装过程中注意设置 root 密码,默认端口 3306 一般不需要修改。第二种是使用 Docker 安装,适合已经有 Docker 环境的人,只需要一条命令就能跑起来:
docker run --name mysql8 -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:8.0这条命令会创建一个名为 mysql8 的容器,root 密码设置为 123456,映射宿主机 3306 端口。使用 Docker 的好处是安装快、卸载干净,不会污染本机环境,对只想验证 Qt 连接数据库的开发者来说非常方便。
安装完成后,建议先用命令行或 MySQL Workbench 验证一下 MySQL 服务是否正常:
mysql -uroot -p123456输入密码后能进入 MySQL 命令行,说明服务已经正常启动。这个验证步骤不要跳过,因为很多 Qt 连接失败的问题,其实在 MySQL 服务本身。
3.3 确认 Qt 是否包含 MySQL 驱动
这是整个项目中最容易踩坑的一步。Qt 默认并不保证所有数据库驱动都存在,尤其是 MySQL 驱动。在 Qt 安装目录下找到子目录 plugins/sqldrivers,检查里面是否有 qsqlmysql.dll 或 qsqlmysql.so。
如果存在,说明当前 Qt 套件内置了 MySQL 驱动。如果不存在,程序运行时会出现类似类似QSqlDatabase: QMYSQL driver not loaded的错误。此时有几种处理办法:
- 重新安装 Qt,在组件选择时勾选对应的 SQL 驱动模块;
- 使用 Qt 自带的驱动编译工具从源码编译 MySQL 驱动;
- 切换到包含 MySQL 驱动的其他 Qt 套件。
同时还需要注意,Qt 程序连接 MySQL 时,在 Windows 下通常依赖 MySQL 的客户端动态库。这个文件在 MySQL 安装目录下,比如 MySQL Server 8.0 的 bin 目录下可以找到 libmysql.dll。最简单的方式是把这个 dll 复制到 Qt 程序的执行目录下,或者加入系统 PATH。如果不处理,程序可能能编译通过,但运行时会提示找不到驱动或无法加载驱动。
3.4 使用 Qt Creator 还是 VSCode
很多刚接触 C++ 的同学已经习惯在 VSCode 里写代码,到 Qt 项目时也倾向于继续用 VSCode。我的判断是:第一个 Qt 项目强烈建议使用 Qt Creator。
原因有几点。Qt Creator 是 Qt 官方提供的 IDE,它内置了 GUI 界面设计器,双击 .ui 文件就能拖拽按钮、输入框、表格,自动生成界面代码。同时它支持 qmake 和 CMake 两种构建方式,能自动识别当前 Qt 套件,避免了在 VSCode 里手动配置 Include 路径、链接库、编译器等一系列麻烦。
用 VSCode 做 Qt 开发当然可行,但前提是你已经熟悉 CMake 或 qmake 的配置,知道如何设置编译任务,能够自己排查头文件找不到、链接失败的问题。这些对新手来说,往往比业务逻辑本身更劝退。所以,第一遍跑通项目时,先用 Qt Creator,等理解了这个流程,再用 VSCode 也不迟。
4. 数据库设计与初始化脚本
这个项目需要两张表,分别承担不同的职责。user 表用于登录验证,保存用户名和密码;student 表用于演示普通业务数据的增删改查,方便你在主窗口用表格展示。
实际项目中密码不应该明文保存,应该使用哈希算法处理。为了让你先跑通整个流程,初始化脚本里暂用明文密码,但文章后面会专门讲工程化改造建议。
CREATE DATABASE IF NOT EXISTS qt_demo DEFAULT CHARACTER SET utf8mb4; USE qt_demo; CREATE TABLE IF NOT EXISTS `user` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `username` VARCHAR(50) NOT NULL UNIQUE, `password` VARCHAR(64) NOT NULL, `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; INSERT INTO `user` (`username`, `password`) VALUES ('admin', '123456'), ('test', '123456'); CREATE TABLE IF NOT EXISTS `student` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(50) NOT NULL, `score` DECIMAL(5,2) DEFAULT 0, `remark` VARCHAR(200) DEFAULT '' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; INSERT INTO `student` (`name`, `score`, `remark`) VALUES ('张三', 88.50, '第一次测试'), ('李四', 92.00, '进步明显'), ('王五', 75.00, '需要加油');注意几个细节。数据库和表的字符集统一使用 utf8mb4,这是为了支持中文和完整的 Unicode 字符。user表里用了反引号包裹,因为 user 在某些 SQL 模式下可能与系统标量逻辑有关系,用反引号可以避免歧义。student 表里的score字段类型为 DECIMAL(5,2),可以保存带两位小数的成绩。
初始化脚本可以在 MySQL 命令行中执行,也可以在 MySQL Workbench 中执行,或者用图形化工具导入。执行后有 3 条 user 记录和 3 条 student 记录,供后面登录测试和表格显示使用。
5. Qt 工程搭建与数据库连接
5.1 创建项目并添加 SQL 模块
在 Qt Creator 中新建一个 Qt Widgets Application 项目,项目名称可以命名为 QtMysqlDemo。创建后在 .pro 文件中添加 sql 模块。.pro 是 qmake 的工程文件,Qt Creator 会自动生成大部分内容,我们需要手动确认以下配置:
QT += core gui sql greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = QtMysqlDemo TEMPLATE = app SOURCES += \ main.cpp \ mainwindow.cpp \ dbmanager.cpp \ logindialog.cpp HEADERS += \ mainwindow.h \ dbmanager.h \ logindialog.h FORMS += \ mainwindow.ui \ logindialog.uiQT += core gui sql表示引入 Qt SQL 模块。注意因为项目启用了 QString、QSqlDatabase 等类,如果缺少 sql 模块,编译时会直接报找不到头文件。FORMS里列出的 .ui 文件是 Qt Designer 生成的界面文件。
5.2 编写数据库连接类 DBManager
数据库连接最好封装成一个管理类。整个程序只需要一个数据库连接,所以使用单例模式最合适。这样登录对话框和主窗口调用的是同一个连接,不会因为重复创建连接导致资源浪费。
头文件 dbmanager.h 内容如下:
#ifndef DBMANAGER_H #define DBMANAGER_H #include <QSqlDatabase> #include <QSqlQuery> #include <QSqlError> #include <QVariant> class DBManager { public: static DBManager& instance(); bool connect(const QString &host, int port, const QString &user, const QString &password, const QString &dbName); bool isOpen() const; QSqlDatabase database() const; private: DBManager(); DBManager(const DBManager&) = delete; DBManager& operator=(const DBManager&) = delete; QSqlDatabase m_db; }; #endif // DBMANAGER_H对应的实现文件 dbmanager.cpp 内容如下:
#include "dbmanager.h" #include <QDebug> DBManager& DBManager::instance() { static DBManager manager; return manager; } DBManager::DBManager() { m_db = QSqlDatabase::addDatabase("QMYSQL"); } bool DBManager::connect(const QString &host, int port, const QString &user, const QString &password, const QString &dbName) { m_db.setHostName(host); m_db.setPort(port); m_db.setUserName(user); m_db.setPassword(password); m_db.setDatabaseName(dbName); if (!m_db.open()) { qCritical() << "数据库连接失败: " << m_db.lastError().text(); return false; } QSqlQuery query(m_db); query.exec("SET NAMES utf8mb4"); return true; } bool DBManager::isOpen() const { return m_db.isOpen(); } QSqlDatabase DBManager::database() const { return m_db; }这段代码有几个值得注意的地方。QSqlDatabase::addDatabase("QMYSQL")指定驱动类型为 QMYSQL,如果这一步失败,通常就是因为前文说的驱动缺失。open()是真正建立连接的动作,连接失败时 lastError() 会给出具体原因。SET NAMES utf8mb4是额外执行的一条编码设置语句,目的是减少中文乱码出现的概率。
在 main.cpp 中,程序启动后的第一件事就是尝试建立数据库连接:
#include <QApplication> #include <QMessageBox> #include "dbmanager.h" #include "logindialog.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); if (!DBManager::instance().connect("127.0.0.1", 3306, "root", "123456", "qt_demo")) { QMessageBox::critical(nullptr, "错误", "数据库连接失败,请检查 MySQL 服务状态和连接参数"); return -1; } LoginDialog loginDlg; loginDlg.show(); return a.exec(); }注意这里把数据库连接参数的获取直接写死在代码里了,目的是先把流程跑通。后面工程化章节会介绍如何把这些配置放到独立文件中。
5.3 实现登录验证功能
登录对话框可以使用 Qt Designer 创建,界面放两个 QLabel、两个 QLineEdit 和一个 QPushButton。用户名输入框起名 usernameEdit,密码输入框起名 passwordEdit,登录按钮起名 loginBtn。
在 logindialog.cpp 中实现登录逻辑:
#include "logindialog.h" #include "dbmanager.h" #include "mainwindow.h" #include <QMessageBox> #include <QSqlQuery> #include <QSqlError> #include <QVariant> LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent) { // 假设通过 ui 指针访问界面控件 connect(ui->loginBtn, &QPushButton::clicked, this, &LoginDialog::onLoginClicked); } void LoginDialog::onLoginClicked() { QString username = ui->usernameEdit->text().trimmed(); QString password = ui->passwordEdit->text().trimmed(); if (username.isEmpty() || password.isEmpty()) { QMessageBox::warning(this, "提示", "用户名和密码不能为空"); return; } QSqlQuery query(DBManager::instance().database()); query.prepare("SELECT id, username FROM user WHERE username = :username AND password = :password"); query.bindValue(":username", username); query.bindValue(":password", password); if (!query.exec()) { QMessageBox::critical(this, "错误", "查询失败: " + query.lastError().text()); return; } if (query.next()) { QMessageBox::information(this, "成功", "登录成功,欢迎 " + username); MainWindow *w = new MainWindow; w->show(); this->close(); } else { QMessageBox::warning(this, "登录失败", "用户名或密码不正确"); } }这里有一个非常关键的习惯:使用prepare配合bindValue,而不是把用户名密码直接拼进 SQL 字符串。拼字符串不仅容易引起语法错误,还会带来 SQL 注入风险。所谓 SQL 注入,就是用户在输入框里输入特殊字符,改变了 SQL 语句本身的含义。参数绑定可以防止这类问题,是数据库开发的基本要求。
5.4 主窗口使用 QSqlTableModel 显示数据
登录成功后进入主窗口。主窗口里放一个 QTableView 和一个“保存修改”按钮,用 QSqlTableModel 把 student 表映射到表格中。
在 mainwindow.cpp 中实现:
#include "mainwindow.h" #include "dbmanager.h" #include <QSqlTableModel> #include <QMessageBox> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { // 假设 ui 指针已经初始化,包含 tableView 和 saveBtn model = new QSqlTableModel(this, DBManager::instance().database()); model->setTable("student"); model->setEditStrategy(QSqlTableModel::OnManualSubmit); model->setHeaderData(1, Qt::Horizontal, "姓名"); model->setHeaderData(2, Qt::Horizontal, "成绩"); model->select(); ui->tableView->setModel(model); ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); connect(ui->saveBtn, &QPushButton::clicked, this, &MainWindow::onSaveClicked); } void MainWindow::onSaveClicked() { if (!model->submitAll()) { QMessageBox::critical(this, "错误", "保存失败: " + model->lastError().text()); } else { QMessageBox::information(this, "成功", "数据已保存到数据库"); } }setEditStrategy(QSqlTableModel::OnManualSubmit)表示修改表格中的数据后,不会立即写回数据库,而是等你调用submitAll()时才统一提交。这样设计的好处是方便做一次性的取消或确认,适合数据管理类场景。
到这里,整个项目已经具备了一个最小可用闭环:启动程序后连接数据库,弹出登录窗口,登录成功后进入主窗口,主窗口表格里显示 student 表的数据,可以在表格里双击修改,然后点击保存写回 MySQL。
6. 运行验证与效果检查
写代码只是第一步,验证才是真正检验理解程度的地方。建议按以下步骤操作:
- 确认 MySQL 服务已经启动,使用命令行
mysql -uroot -p123456能正常进入; - 在 MySQL 中执行上一节提供的初始化 SQL 脚本;
- 在 Qt Creator 中打开项目,选择正确的编译套件,点击构建运行;
- 程序启动后如果弹出“数据库连接失败”,优先检查驱动和连接参数;
- 登录窗口输入 admin / 123456,预期弹出登录成功的提示,并进入主窗口;
- 输入错误密码,预期弹出“用户名或密码不正确”的警告,不会进入主窗口;
- 主窗口表格应显示 3 条 student 记录,双击某个字段修改后点击保存,再次打开程序数据仍然存在。
验证点可以整理成下表:
| 验证点 | 操作 | 预期结果 |
|---|---|---|
| 数据库连接 | 启动程序 | 不报错,正常弹出登录窗口 |
| 空输入校验 | 用户名和密码都留空,点击登录 | 弹出提示“用户名和密码不能为空” |
| 正确登录 | 输入 admin / 123456 | 提示登录成功,进入主窗口 |
| 错误登录 | 输入 admin / wrong | 提示用户名或密码不正确 |
| 表格显示 | 进入主窗口 | 显示 student 表的 3 条数据 |
| 修改保存 | 双击表格修改成绩,点击保存 | 修改成功,数据持久化到 MySQL |
如果修改数据后在 MySQL 命令行里执行SELECT * FROM student;,能看到更新后的值,说明表格保存功能正常。
7. 常见问题与排查思路
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 启动提示 QMYSQL driver not loaded | Qt 的 sqldrivers 目录没有 qsqlmysql 驱动插件 | 检查 Qt 安装目录 plugins/sqldrivers | 重装 Qt 勾选 SQL 模块,或使用自带驱动编译工具 |
| 编译通过但运行报驱动无法加载 | 缺少 MySQL 客户端动态库 libmysql.dll | 查看运行目录是否有该文件 | 将 MySQL 安装目录 bin 下的 libmysql.dll 复制到程序目录 |
| 连接失败:Can't connect to MySQL server | MySQL 服务未启动,或端口、主机名配置错误 | 用命令行尝试连接 MySQL | 启动 MySQL 服务,检查端口和主机名 |
| 认证插件报错 caching_sha2_password | MySQL 8.0 默认认证插件与旧版驱动不兼容 | 查看错误日志中的认证信息 | 创建用户时指定 mysql_native_password,或更换新版驱动 |
| 中文乱码 | 数据库、表、连接字符集不一致 | 分别检查库表字符集和 Qt 连接设置 | 统一使用 utf8mb4,连接后执行 SET NAMES utf8mb4 |
| 点击登录按钮无反应 | 信号槽没有正确连接,或按钮对象名不对 | 在槽函数中加 qDebug 输出 | 检查 connect 语句和控件 objectName |
| 编译报找不到 QSqlDatabase | 缺少 sql 模块 | 查看 .pro 文件 | 在 .pro 中添加QT += sql |
| 程序发布后在其他电脑运行提示缺 DLL | Qt 运行库和 MySQL 客户端库未打包 | 使用 windeployqt 工具 | 发布时带上 Qt 依赖库和 libmysql.dll |
8. 工程化建议:别让第一个项目只停留在“能跑”
第一个项目跑通之后,很多人会进入一种“舒适状态”:代码能编译,功能能使用,然后就不想动了。如果只是做课程设计,这样确实可以交差。但如果你想继续往 C++ 桌面开发方向走,下面几个问题值得在后续迭代中认真处理。
第一,数据库连接配置不要写死在代码里。可以用 QSettings 读取 config.ini 文件,也可以读取环境变量。这样换一台机器、换一个数据库环境时不需要重新编译代码。配置项至少包括数据库主机、端口、用户名、密码、数据库名称。
第二,密码安全问题。当前登录演示直接使用明文密码校验,这在真实项目中是不可接受的。正确做法是在数据库里保存密码的哈希值,比如使用 Qt 的 QCryptographicHash 计算 SHA-256,登录时对用户输入做同样哈希再比对。更严谨的做法是引入盐值,防止哈希碰撞攻击。
第三,数据库操作不要全部堆在主线程里。当表数据量变大,或者 SQL 查询特别复杂时,界面会发生明显的卡顿。这里可以引入 Qt 的多线程机制,把耗时的 SQL 操作放到 QThread 或 QtConcurrent 中执行,执行完成后再通过信号槽把结果传回主线程更新界面。注意子线程中不能直接操作界面控件,这是 Qt 线程模型的基本约束。
第四,事务与错误处理。当一次操作需要同时更新多张表时,必须使用事务保证原子性。QSqlDatabase 提供了 transaction() 和 commit(),在出错时调用 rollback() 回滚。不要忽略 QSqlQuery::lastError() 的结果,日志里应该有完整的错误信息,方便定位问题。
第五,目录结构和命名规范。建议从项目一开始就保持清晰的结构,把数据库操作类、业务逻辑类、界面类分开。类名使用大驼峰,函数和变量名使用小驼峰,文件命名与类名保持一致。这样可以极大提升代码可读性,也为后续扩展留出空间。
第六,使用版本控制。源码应该从一开始就用 Git 管理,提交信息写清楚改动原因。Qt Creator 内置了 Git 支持,操作并不复杂。课程设计或面试项目里,Git 提交历史本身就能证明你的工程能力。
第七,发布与打包。Qt 程序发布不是直接把 exe 拷走就能用的。Windows 下可以使用 windeployqt 工具自动收集 Qt 依赖库,然后再把 MySQL 客户端库一起打包,最后用 Inno Setup 或 NSIS 生成安装程序。发布之前还要在干净的虚拟机里测试一遍,避免漏掉运行库。
9. 总结与下一步学习方向
这篇文章里,我们完成了一个最小但有完整数据流的 Qt6 + MySQL 项目:从环境安装、数据库初始化,到编写数据库连接类,再到实现登录验证和表格数据展示。整个过程覆盖了 Qt SQL 模块的几个核心类,以及驱动加载、编码、连接异常等常见问题。
把这套流程走通之后,接下来有几条清晰的学习路径。如果想继续提升界面表现力,可以学习 QSS 样式表,让程序摆脱默认样式的“工具感”;如果想做更复杂的表格交互,可以学习 QTableView 的委托和自定义 Model;如果想往客户端服务器架构发展,可以学习 Qt Network 模块,把 MySQL 操作收敛到服务端,客户端通过网络请求访问数据;如果想把项目做得更大,可以学习 CMake 替代 qmake 来管理工程,并研究如何在 Windows 和 Linux 上交叉发布。
这套“界面 + 数据库”的最小闭环,其实是一块很好的基石。后面无论加图表、加报表、加权限管理,还是把单机程序改造成多人使用的客户端服务器结构,本质上都是在这个闭环上不断补模块。建议把当前版本的源码完整保存,整理成带注释的工程,既方便自己复习,也能在课程设计或求职项目中继续迭代。