基于Qt与SQLite的学生信息管理系统:架构、实现与避坑指南
简介《基于Qt学生信息管理系统》是一份面向C初学者的完整实训项目资料适合作为课程大作业或自学参考。项目基于Qt框架与SQLite数据库构建C/S架构的桌面应用覆盖学生信息的增删改查等核心功能演示了GUI编程与数据库交互的完整流程。资源共包含5个文件压缩包约29.6MB涵盖RAR源码压缩包、SQL数据库脚本、SQLite备份文件、MP4操作视频及DOC说明文档。各文件分别用于代码学习、环境初始化、数据预览和操作演示可快速复现整个系统。目前已有2592人学习下载。通过阅读说明文档和观看视频可掌握从界面设计到业务逻辑实现的具体步骤依托源码与数据库脚本还能进一步研究SQL语句调用、表结构设计等细节对理解C/S架构在桌面应用中的落地方式很有帮助。1. 基于Qt的学生信息管理系统能跑、能答辩、还能当脚手架一提到学生信息管理系统多数人第一反应是“又是课程设计”。但手里这份用 C Qt SQLite3 做出来的桌面端源码不是那种只放了个登录框的演示项目登录校验、学生台账、增删改查、按专业统计和检索都已经落地数据库用文件型 SQLite3不用装服务拷贝文件夹就能跑。对正在选毕设课题或想快速搭一套内部小工具的从业者来说它最大的价值不是“某个功能”而是整套代码结构和数据库交互方式可以直接抄。我从拿到源码到完全跑通、改成自己的项目前后只花了两个晚上大部分时间还耗在踩 Qt 环境坑上。2. 技术选型与分层Qt 5、SQLite 3 和一套可复用的工程结构2.1 为什么是 Qt 5 SQLite 3而不是更“新”的组合先说结论这套资源锁定的是 Qt 5常见版本是 5.15.x SQLite 3 C11/14放在这个组合里代码能最大程度保持干净。Qt 6 虽然已经普及但它默认要求 C17部分旧 API 被移除或改名比如QRegExp换成了QRegularExpressionQDesktopWidget被拆掉拿到手若想在 Qt 6 上直接编译报错会让人劝退。所以优先按原资源的 Qt 5 环境来跑跑通后再决定要不要迁移。SQLite 3 的选择理由是“零配置”。它不需要像 MySQL 那样安装服务、指定端口、管理账号student.db就是一个普通文件放在工程目录下即可。对单机版信息管理系统来说这种文件型数据库的读性能完全够用而且备份就是复制文件。非要换 MySQL反而要考虑驱动QMYSQL的编译问题动态链接库版本不匹配会直接导致程序连不上库那种排查成本对初学用户不友好。2.2 工程结构把界面、业务和数据库拆开我见过不少 Qt 项目所有代码堆在MainWindow.cpp里槽函数里直接写 SQL三个月后自己都看不懂。这套资源的目录是典型的三层划分StudentManager/ ├── StudentManager.pro ├── main.cpp ├── ui/ │ ├── MainWindow.h │ ├── MainWindow.cpp │ ├── LoginDialog.h │ └── LoginDialog.cpp ├── db/ │ ├── DatabaseManager.h │ └── DatabaseManager.cpp └── models/ ├── StudentTableModel.h └── StudentTableModel.cpp.pro文件是 qmake 工程描述里面用QT core gui sql widgets声明依赖db/DatabaseManager负责连接和建表models层做数据模型封装ui层只处理用户交互。这样拆的好处是如果哪一天要从 SQLite 换到 PostgreSQL只需要改db目录下的代码界面完全不动。2.3 数据库连接与建表代码里的几个关键点数据库管理类是整个系统的地基值得逐行读。初始化方法如下// DatabaseManager.cpp #include DatabaseManager.h #include QSqlDatabase #include QSqlQuery #include QSqlError #include QDebug bool DatabaseManager::init() { // 使用具名连接避免与其他连接混淆 if (QSqlDatabase::contains(student_conn)) { db QSqlDatabase::database(student_conn); } else { db QSqlDatabase::addDatabase(QSQLITE, student_conn); } db.setDatabaseName(student.db); if (!db.open()) { qDebug() 数据库打开失败: db.lastError().text(); return false; } createTables(); return true; }addDatabase的第二个参数是连接名这个细节很多初学朋友会忽略。如果不给名字默认连接是空字符串当程序里同时打开多个数据库时后打开的那个会把默认连接顶掉导致第一个连接失效。所以这里显式命名成student_conn后续所有查询都用QSqlDatabase::database(student_conn)取连接代码更稳。建表函数采用CREATE TABLE IF NOT EXISTS保证重复运行不报错void DatabaseManager::createTables() { QSqlQuery query(db); bool ok query.exec( CREATE TABLE IF NOT EXISTS student ( id INTEGER PRIMARY KEY AUTOINCREMENT, student_no TEXT UNIQUE NOT NULL, name TEXT NOT NULL, gender TEXT, age INTEGER, major TEXT, phone TEXT)); if (!ok) { qDebug() 建表失败: query.lastError().text(); } }字段设计上id是自增主键student_no学号加了UNIQUE约束这是逻辑层不重复录入的第一道保险phone字段建议用 TEXT 而不用 INTEGER因为手机号前导零和长度问题在数值类型下会出现诡异丢失。建表时顺手把PRAGMA foreign_keys ON打开也是好习惯后面若要加score表做外键关联不必回头重建表。3. 登录、增删改查和统计四个核心模块的落法3.1 登录模块密码不能明文存储这套系统的登录模块做成了独立LoginDialog先验证再进主窗口。资源里默认管理员账号是admin但数据库里存的是 SHA-256 散列值而不是明文这点值得给好评。验证逻辑可以抽象成下面这段// LoginDialog.cpp #include QCryptographicHash bool LoginDialog::checkPassword(const QString username, const QString password) { // 先取出该用户名对应的密码散列 QSqlQuery query; query.prepare(SELECT password_hash FROM users WHERE username :name); query.bindValue(:name, username); if (!query.exec() || !query.next()) { return false; // 用户不存在 } QString storedHash query.value(0).toString(); // 用户输入内容重新做一次 SHA-256 QByteArray inputHash QCryptographicHash::hash( password.toUtf8(), QCryptographicHash::Sha256); return storedHash.compare(inputHash.toHex(), Qt::CaseInsensitive) 0; }注意比较散列值时应该用Qt::CaseInsensitive吗其实十六进制散列通常小写而有些数据库驱动可能返回大写加上忽略大小写能避免这种意外。密码加盐是更稳妥的做法但对课程设计级别的学生信息管理系统先做到不明文存库已经比绝大多数示例代码进了一步。这段代码还用到了prepare绑定参数而不是直接拼字符串目的就是防 SQL 注入这也是所有拼接输入的通用底线。3.2 新增与编辑表单校验比想象中重要新增学生信息时最忌讳的是用户填了一个非法学号数据库UNIQUE约束直接报错而界面只弹一个生硬的 QMessageBox。本项目在提交前做了三层校验学号非空、学号长度不超过 20、年龄必须在 0 到 150 之间。核心入库函数如下bool StudentDao::insertStudent(const StudentInfo stu) { QSqlQuery query(db); query.prepare( INSERT INTO student (student_no, name, gender, age, major, phone) VALUES (:no, :name, :gender, :age, :major, :phone)); query.bindValue(:no, stu.studentNo); query.bindValue(:name, stu.name); query.bindValue(:gender, stu.gender); query.bindValue(:age, stu.age); query.bindValue(:major, stu.major); query.bindValue(:phone, stu.phone); if (!query.exec()) { qDebug() 插入失败: query.lastError().text(); return false; } return true; }bindValue的顺序和 SQL 里占位符一一对应。占位符用冒号前缀比?占位符可读性高。这里有个值得养成的习惯exec()之后哪怕直觉没问题也要检查返回值再把lastError()打出来否则SQL写错字段名会被静默吞掉用户看到的是“点了新增没反应”。编辑功能本质上和插入一致只是把INSERT换成UPDATE并把主键id作为更新条件UPDATE student SET student_no:no, name:name, gender:gender, age:age, major:major, phone:phone WHERE id:id;不管新增还是编辑QSqlQuery都要在函数作用域里声明让它随函数退出释放。若把查询对象当成成员变量长期持有SQLite 的写锁没有及时释放下次写入就会报database is locked。3.3 删除操作先确认再删最后重置自增列删除模块做了“二次确认”弹窗这是信息管理类系统必备的交互防止手滑。删除语句简单但自增主键的处理有说法删除最高 id 后插入新记录会接着旧的 id 继续增长不会重用被删的 id。有些任课老师会要求“删完了数据重新从 1 开始”实现方式是在删除完成后执行一条 SQLDELETE FROM sqlite_sequence WHERE name student;sqlite_sequence是 SQLite 内部维护自增计数的表手动清掉后下一次插入就会从 1 重新编号。要注意的是这条语句不是标准 SQL 的一部分仅 SQLite 支持如果哪天换库必须删掉。3.4 模糊查询、精确查询与统计视图查询模块是本项目的主菜单重点它的几个查询条件做成了一行输入框加下拉框。常见做法是条件为空时查出全部数据条件非空时用WHERE拼接。为了防止拼接出错推荐统一用prepare加动态拼 SQL 文本void StudentDao::queryStudents(const QString keyword, const QString field) { QSqlQuery query(db); QString sql SELECT * FROM student WHERE 1 1; if (!keyword.isEmpty()) { sql QString( AND %1 LIKE :kw).arg(field); } sql ORDER BY student_no; query.prepare(sql); if (!keyword.isEmpty()) { query.bindValue(:kw, % keyword %); } query.exec(); }field不能直接让用户传必须映射成白名单中的字段名例如major、name、student_no否则用户输入就会变成 SQL 注入入口。这里先把字段名做一次映射再拼 SQL是典型的参数安全姿势。LIKE 两侧的%是模糊匹配的关键%张%能匹配“张三”和“小张”但在 SQLite 里它默认只匹配 ASCII 字符中文字符匹配要确保数据库文件本身是 UTF-8 编码否则“输入中文查不出结果”的坑马上就来。统计功能用 GROUP BY 做专业人数分布模型绑定到表格视图上可以直接出报表QSqlQueryModel *model new QSqlQueryModel(this); model-setQuery(SELECT major AS 专业, COUNT(*) AS 人数 FROM student GROUP BY major, db); ui-tableView-setModel(model);QSqlQueryModel是只读模型适合这种统计结果展示数据交互如果还要支持编辑应该换QSqlTableModel并在视图上设置编辑策略。这两种模型选错会出现在线编辑失效的问题但不算 bug是模型能力边界决定的。4. 避坑与排查五个最常见的编译与运行期问题4.1 报错QSqlDatabase: QSQLITE driver not loaded现象程序启动后控制台打印QSqlDatabase: QSQLITE driver not loaded接着数据库打开失败。原因Qt 安装目录下的plugins/sqldrivers目录没有被拷贝到可执行文件目录也可能是因为程序用了 MinGW 编译的 Qt却把 MSVC 编译的 SQLite 驱动插件放进了发布目录动态库 ABI 不兼容。解决先在开发环境确认qsqlite.dll或libqsqlite.so存在于Qt安装目录/plugins/sqldrivers。运行时把整个sqldrivers文件夹按相对路径放到可执行文件旁边也可以在代码里显式指定插件路径QCoreApplication::addLibraryPath( QCoreApplication::applicationDirPath() /plugins);这样无论目录怎么移动程序都会先去自己的plugins目录找驱动。4.2 界面输入中文正常入库后变成乱码现象在输入框里输入“张三”QSqlQueryModel里查出来却显示“寮犱笁”或问号直接命令行查数据库文件也是乱码。原因源文件本身的编码不是 UTF-8或者数据库创建时继承了系统本地编码Windows 下常见 GBK。SQLite 默认编码是 UTF-8如果 Qt 端把 QString 转成了本地编码再写入就发生转码错乱。解决所有.cpp、.h文件用 UTF-8 编码保存并在查询前执行PRAGMA encoding UTF-8。Qt 5 里不要在源文件中用tr(中文)外层的字符串常量的历史坑直接用QStringLiteral(中文)或u8中文即可避免编译器把宽字符搞乱。4.3 按钮点击无反应信号槽连接没接上现象界面正常显示登录按钮点了没任何响应控制台偶尔输出No such slot MainWindow::on_login_Btn_clicked()。原因Qt 早期版本用Q_OBJECT宏加槽函数名自动连接但函数签名少写一个参数、函数被重载、或者用了private slots却没加Q_OBJECT都会让连接静默失败。解决统一使用 Qt 5 的函数指针式连接connect(ui-loginBtn, QPushButton::clicked, this, LoginDialog::onLoginClicked);如果槽函数是重载版本比如onLoginClicked(bool)需要加函数指针转换connect(ui-loginBtn, QPushButton::clicked, this, qOverload(LoginDialog::onLoginClicked));qOverload避免了按钮传参类型导致找不到槽函数的困惑。排查时优先看编译输出里的“No such slot”警告所有信号槽问题都会在这里露出马脚。4.4 上万条数据加载时界面卡死现象程序打开主界面后转圈标题栏显示“未响应”数据量大时加载要好几秒。原因在主线程里执行了全表SELECT *并把结果填充到表格模型期间界面事件循环被阻塞。解决大数据量场景做分页查询。限制一次加载数量并配合滚动加载是简单有效的方案query.prepare(SELECT * FROM student LIMIT :limit OFFSET :offset); query.bindValue(:limit, 100); query.bindValue(:offset, currentOffset);单机桌面管理系统的数据量通常在几百到几千条但如果历史数据导入后达到数万条分页是让界面保持流畅的最省事手段。如果坚持一次性加载可以把查询放进QtConcurrent::run完成后通过信号回传结果但那套线程与模型的交互复杂度远超分页。4.5 INSERT 执行成功但表里没有新数据现象代码返回true界面上没有闪退但数据表里查不到新增记录。原因最常见的有两种。第一种是插入成功后没有刷新QSqlTableModel模型缓存还是旧快照第二种是程序写了两个数据库连接一个连接写入另一个连接查询而 SQLite 在这种场景下存在连接级的数据隔离。解决插入成功后显式调用模型的select()或者重新setQuery刷新视图。多连接场景统一走同一个连接名不要在每个函数里都执行QSqlDatabase::addDatabase(QSQLITE)那会悄悄创建多个连接并让日志检索极其混乱。若确实需要多连接查询前对执行方式设置QSqlQuery::setForwardOnly(true)也能避免模型持有数据快照不刷新。5. 进阶打磨把“交作业版本”改成“能反复用的工具”5.1 用 QSS 换掉默认外观默认的 Qt 控件外观在答辩时容易被扣印象分。在 main.cpp 里加载一份 qss 文件三行代码就能让整体观感上一个台阶QFile qssFile(:/style/cloud.qss); qssFile.open(QFile::ReadOnly); app.setStyleSheet(QString::fromUtf8(qssFile.readAll()));QSS 语法很像 CSS主要改QPushButton、QLineEdit、QTableView的背景、边框和悬停效果。设置一个全局按钮圆角和主色界面立刻不再是“白板教学风”。5.2 一键备份与恢复课程设计答辩时会碰到“数据库文件丢了怎么办”的尴尬。加一个备份按钮本质就是复制文件QFile::copy(student.db, QDateTime::currentDateTime().toString(yyyyMMdd_hhmmss) _student.db);手动备份后可以将备份文件放到backup/目录恢复时把所选备份覆盖回student.db再刷新模型。这套逻辑对任何 SQLite 项目都通用不需要额外引入备份组件。5.3 发布部署别让动态库漏掉程序写完要在别的机器上跑需要把 Qt 的 DLL 一并带上。开发机可以用官方工具自动扫描依赖但自动扫描偶尔会漏掉 SQLite 驱动插件所以发布目录里务必保留sqldrivers/qsqlite.dll。我习惯在打包脚本里显式检查一下windeployqt StudentManager.exe --release --no-translations cp -r Qt安装目录/plugins/sqldrivers ./release/sqldrivers从那以后我每次拿到课程设计源码都会先看一眼.pro文件里的QT sql有没有写再点开main.cpp确认QApplication初始化顺序。很多“跑不起来”的问题一半是环境一半是连接和编码。提前把这些基础工作做完后面改功能、应付追问都能从容不少。希望这份笔记能帮你把“基于 Qt 的学生信息管理系统”从能跑变成能打。本文还有配套的精品资源点击获取

相关新闻

PCB收放板设备视觉系统应用层次选型参考——CCD定位/视觉定位/X-Ray靶点识别对比

PCB收放板设备视觉系统应用层次选型参考——CCD定位/视觉定位/X-Ray靶点识别对比

视觉系统在PCB收放板设备中的应用,从简单的定位引导到复杂的靶点识别,形成了不同的技术层次。不同工序对视觉系统的精度要求、响应速度、识别对象各不相同,对应的配置方案也有差异。本文按视觉系统的功能层次,对比CCD定位、视觉定…

2026/10/15 15:26:14 阅读更多 →
VMware Live Site Recovery 9.0.5.1新功能介绍(站点级容灾编排工具+ vSphere Replication)

VMware Live Site Recovery 9.0.5.1新功能介绍(站点级容灾编排工具+ vSphere Replication)

VMware Live Site Recovery 面向站点级场景,提供端到端、按需启用的灾难恢复能力。底层复制既可采用基于存储阵列的方式,也可使用基于主机的 VMware vSphere Replication,或 VMware 虚拟卷(vVol)复制,具体恢…

2026/10/15 15:26:14 阅读更多 →
JMP统计软件操作指南:数据表、图表与质量分析工具详解

JMP统计软件操作指南:数据表、图表与质量分析工具详解

简介:JMP是由SAS公司开发的交互式统计分析软件,凭借图形化界面与丰富统计功能,常被视为比Minitab更强大的工具。这份培训讲义课件面向质量工程师、数据分析师及统计初学者,系统介绍JMP的数据处理、统计分析及质量改进方法。资源仅…

2026/10/15 15:25:13 阅读更多 →

最新新闻

光学工程师笔试题深度解析:从Zemax实操到公差分析的能力地图

光学工程师笔试题深度解析:从Zemax实操到公差分析的能力地图

简介:这是一份面向光学工程师求职者与光学相关专业学生的笔试真题文档,聚焦光学基础理论与工程应用能力的综合考查。内容涵盖图解法求像、填空题与计算题三大板块:图解法要求判断成像方向、标注理想光学系统基点位置与焦距;填空题…

2026/10/15 16:05:26 阅读更多 →
分数阶傅里叶变换的Matlab代码包:四种实现与图像加密

分数阶傅里叶变换的Matlab代码包:四种实现与图像加密

简介:分数阶傅里叶变换(FRFT)的MATLAB实现代码包,面向信号处理与图像分析方向的开发者及研究人员,解决传统FFT仅能进行0度和90度变换的限制,可在连续角度域对信号进行频谱分析。压缩包内共9个文件&#xff…

2026/10/15 16:05:26 阅读更多 →
ADS耦合器设计源文件改造与仿真验证全指南

ADS耦合器设计源文件改造与仿真验证全指南

简介:面向射频微波电路设计工程师、通信专业高年级学生以及电磁仿真入门者,这是一份基于ADS软件的耦合器设计源文件,适合用于学习定向耦合器在2.4GHz频段下的设计方法,也适合作为同类射频电路设计项目的参考模板。资源围绕中心频率…

2026/10/15 16:05:26 阅读更多 →
Fraunces 可变字体实战指南:桌面端与网页端的安装、选用与变体轴配置

Fraunces 可变字体实战指南:桌面端与网页端的安装、选用与变体轴配置

前端 【免费下载链接】beautiful-web-type In-depth guide to the best open-source typefaces: https://www.beautifulwebtype.com 项目地址: https://gitcode.com/gh_mirrors/be/beautiful-web-type 点击查看 免费下载 Fraunces 是一款由 Undercase Type 的 Phae…

2026/10/15 16:05:26 阅读更多 →
零基础如何写代码?从理解业务开始的学习路径

零基础如何写代码?从理解业务开始的学习路径

零基础如何写代码,是很多想进入软件开发领域的人遇到的第一个问题。常规建议是选一门编程语言,从变量、循环、函数学起,再逐步接触框架和数据库。这条路可行,但周期较长,对只想解决具体业务问题的人来说,投…

2026/10/15 16:05:26 阅读更多 →
AMQP接入物联网平台:连接断开、心跳与消费确认的实战复盘

AMQP接入物联网平台:连接断开、心跳与消费确认的实战复盘

凌晨两点手机震了,我以为是例行告警,结果是“AMQP连接断开”。那条消息来自我们刚上线不久的企业服务器接入物联网平台项目:设备数据本来应该通过 AMQP 通道源源不断回流到后端,结果网关一断,消息全堵在平台侧。我爬起…

2026/10/15 16:04:25 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →