MFC DataGrid 控件实战:数据绑定、格式化与排序避坑指南
简介这份资源面向使用 VC/MFC 进行桌面开发的程序员尤其是需要在对话框或文档程序中嵌入表格控件、展示数据库查询结果的开发者。内容围绕 MFC 中 DataGrid 控件的实际用法展开涵盖将 ADO 记录集绑定为数据源以显示查询结果、通过 CColumns 与 CColumn 对象控制列宽、用 SetNumberFormat 格式化数据如把小于 1 的小数显示为百分数、设置行高实现多行显示以及借助 HeadClick 等消息机制完成排序等常见需求属于可直接对照编码的实战型参考。资源包为 1 个 doc 文档约 226KB内含完整示例代码与工程说明源程序在 VC6.0 英文版、Windows XP 下调试通过便于读者边看边改、快速套用到自己的项目中。目前已有 849 人学习适合希望用微软原生控件替代第三方网格、减少代码细节投入的开发者参考。1. 从一张没人愿意维护的对话框说起MFC DataGrid 控件到底值不值得用接手过一个老工控上位机项目主框架是对话框数据展示区域用的是 MFC 自带的 DataGrid 控件。前任开发者离职后这块代码成了没人敢碰的黑匣子——列宽写死、百分数格式错乱、点表头排序直接崩。我花了两个晚上把 Microsoft DataGrid OLEDB 6.0 控件的接口翻了一遍才发现问题根本不在控件本身而在于大多数人只抄了SetRefDataSource那一行后面的列对象、格式控制、消息映射全没跟上。MFC DataGrid 控件是 VC 环境下用来显示表格数据的 ActiveX 网格控件底层基于 COM通过CDataGrid、CColumns、CColumn三个封装类暴露接口。它最大的优势是跟 Windows 系统兼容性极好升级系统几乎不用改代码适合那些不想引入第三方网格库、又需要快速展示 ADO 查询结果的对话框工程。如果你手头正好有一个 VC6.0 或 VS 的 MFC 项目需要把数据库查询结果塞进网格里并且希望列宽、格式、排序都能自己控制那这份用法梳理就是给你准备的。下面按「显示数据 → 控制外观 → 格式化内容 → 处理事件 → 避坑」的顺序拆开讲每一步都落到能直接抄的代码和参数上。2. 把 ADO 记录集塞进 DataGrid数据源绑定与列对象获取2.1 为什么选 ADO 而不是 ODBC 或 DAO在 MFC 里往 DataGrid 喂数据常见做法有三种ODBC API、DAO、ADO。我一般会选 ADO原因很直接——DataGrid 控件本身是 OLEDB 体系的SetRefDataSource接收的是一个LPUNKNOWN接口指针而 ADO 的Recordset对象底层就是 OLEDB 行集两者对接不需要额外转换层。ODBC 需要先拿到HSTMT再包装DAO 跟 Jet 引擎绑得太死换数据库时改动量大。项目正文里用了一个 ADO 封装类CADODatabase和CADORecordset这是很多老项目的常见做法。如果你手头没有现成封装直接用_ConnectionPtr和_RecordsetPtr智能指针也行原理一样。关键点是DataGrid 要的是Recordset的IUnknown接口不是记录集本身的数据副本所以绑定之后记录集不能提前释放。2.2 绑定数据源的完整代码与参数说明先看一段可以直接放进OnInitDialog或按钮响应函数里的代码// 数据库连接对象和记录集对象通常作为对话框类的成员变量 CADODatabase m_DBCn; CADORecordset m_Rs; CDataGrid m_ctrlDG; // DataGrid 控件绑定的成员变量 // 构造连接字符串Provider 用 Jet 4.0 访问 .mdb 文件 CString strConnection; strConnection.Format(_T(ProviderMicrosoft.Jet.OLEDB.4.0;) _T(Data Sourcenote.mdb)); // 打开数据库失败时弹出提示 if (!m_DBCn.Open((LPCTSTR)strConnection)) { AfxMessageBox(_T(数据库打开失败检查 note.mdb 路径)); return FALSE; } // 把数据库对象关联到记录集再执行查询 m_Rs.SetDatabase(m_DBCn); m_Rs.Open(_T(select * from test;)); // 关键一步把 Recordset 的 IUnknown 指针交给 DataGrid m_ctrlDG.SetRefDataSource((LPUNKNOWN)m_Rs.GetRecordset());逻辑说明SetDatabase只是让记录集知道去哪个库执行 SQL真正打开记录集的是Open。GetRecordset()返回的是底层_RecordsetPtr的接口强制转成LPUNKNOWN后传给SetRefDataSource。参数方面连接字符串里的Data Source可以是绝对路径或相对路径相对路径以工程工作目录为基准调试时经常因为工作目录不对导致找不到文件后面避坑章节会细说。2.3 取得列对象CColumns 与 CColumn 的关系数据绑上去之后网格会自动根据记录集字段生成列。但如果你想改列宽、改标题、改格式就必须先拿到列对象。DataGrid 的列集合是CColumns单列是CColumn获取方式如下// 取得列集合 CColumns cols m_ctrlDG.GetColumns(); // 用 VARIANT 指定列索引0 表示第一列 VARIANT vt; vt.vt VT_I2; vt.iVal 0; CColumn col cols.GetItem(vt); // 设置列宽单位是像素 col.SetWidth(120);这里有个容易翻车的地方GetItem的参数是VARIANT不是简单的int。很多示例代码直接写cols.GetItem(0)在部分编译器上能过但运行时可能因为 VARIANT 类型不明确而取不到列。稳妥做法是显式构造VT_I2类型的 VARIANT。另外列索引从 0 开始跟数据库字段顺序一致但如果 SQL 里用了select *字段顺序由表结构决定改表之后列索引可能错位建议显式写出字段名。提示CColumns和CColumn是控件插入时生成的封装类如果你在类向导里只选了CDataGrid没选这两个代码编译会报类型未定义。重新走一遍「添加类」流程把三个类都勾上。3. 列宽、行高与显示格式让网格不再像半成品3.1 列宽控制的三种粒度和适用场景列宽设置看起来简单但实际项目里需求往往分三层全局统一宽度、按列单独设宽、根据内容自适应。DataGrid 原生只支持前两种自适应需要自己算。全局设置可以用SetDefColWidth单位是像素// 所有未单独设置宽度的列默认宽度为 100 像素 m_ctrlDG.SetDefColWidth(100);按列设置就是前面提到的col.SetWidth(fWidth)。我一般会在对话框初始化时遍历所有列根据字段类型给不同宽度——文本字段宽一些数值和日期窄一些。比如CColumns cols m_ctrlDG.GetColumns(); long nColCount cols.GetCount(); // 获取列总数 for (long i 0; i nColCount; i) { VARIANT vt; vt.vt VT_I4; vt.lVal i; CColumn col cols.GetItem(vt); // 前两列是名称和编号给宽一点 if (i 2) col.SetWidth(150); else col.SetWidth(90); }参数说明GetCount()返回long类型循环变量别用int否则在 64 位编译下会有警告。vt.vt用VT_I4对应long比VT_I2更通用。3.2 行高与多行显示的取舍项目正文里提到SetRowHeight(20)实现多行显示这里要澄清一个概念SetRowHeight设置的是单行高度不是「多行显示」。DataGrid 默认每行显示一条记录行高加大只是让单元格内容更宽松不会把一条记录拆成多行。真正要在一行里显示多行文本需要单元格内容包含换行符并且列样式允许换行。// 设置所有行的统一高度为 24 像素 m_ctrlDG.SetRowHeight(24); // 如果某列内容较长可以开启该列的自动换行 VARIANT vt; vt.vt VT_I2; vt.iVal 3; CColumn col m_ctrlDG.GetColumns().GetItem(vt); col.SetWrapText(TRUE); // 允许换行SetWrapText是CColumn的方法设为TRUE后单元格里带\n的文本会折行显示行高会自动撑开。注意这个属性对性能有影响数据量大时不要全列开启。3.3 数字格式化的实际效果与格式串写法把小于 1 的小数显示成百分数是项目正文里的典型需求。SetNumberFormat接收的是格式字符串规则跟 VB 的Format函数类似VARIANT vt; vt.vt VT_I2; vt.iVal 2; // 第三列假设是比率字段 CColumn col m_ctrlDG.GetColumns().GetItem(vt); // 显示成百分数保留一位小数 col.SetNumberFormat(_T(0.0%));格式串0.0%的含义0表示占位符不足补零.是小数点%会把原数值乘以 100 并追加百分号。如果原值是0.156显示为15.6%。常见格式串还有格式串原值显示结果适用场景0.003.141593.14保留两位小数#,##012345671,234,567千分位整数0.0%0.15615.6%比率百分数yyyy-MM-dd日期值2025-01-15日期格式化0.00E00123451.23E04科学计数法注意SetNumberFormat只对数值型字段生效文本字段设了也没用。如果发现格式没变化先确认数据库里该字段的类型是不是数字或货币。4. 表头点击排序与消息映射让网格能交互4.1 HeadClick 消息的映射方式DataGrid 控件支持表头点击事件消息名是HeadClick。在 MFC 里给 ActiveX 控件加事件处理跟普通控件不太一样需要走类向导的「消息映射」或者手动写BEGIN_EVENTSINK_MAP。手动映射的写法如下放在对话框类的.cpp文件里// 在类声明里加上事件处理函数声明 afx_msg void OnHeadClickDatagrid1(short ColIndex); // 在 BEGIN_MESSAGE_MAP 之后、END_MESSAGE_MAP 之前加事件映射 BEGIN_EVENTSINK_MAP(CTestGridDlg, CDialog) ON_EVENT(CTestGridDlg, IDC_DATAGRID1, 2, OnHeadClickDatagrid1, VTS_I2) END_EVENTSINK_MAP()参数说明IDC_DATAGRID1是控件的资源 ID2是HeadClick事件的调度 ID这个值由控件类型库决定不同版本可能不同可以在类向导生成的事件映射里确认VTS_I2表示处理函数接收一个short参数即列索引。4.2 排序逻辑的实现与记录集重查拿到列索引之后排序有两种做法一是对已绑定的记录集重新排序二是重新执行带ORDER BY的 SQL。第一种需要记录集支持排序ADO 的Recordset可以设Sort属性但 DataGrid 绑定后不一定实时刷新。我一般用第二种简单可靠void CTestGridDlg::OnHeadClickDatagrid1(short ColIndex) { // 根据列索引映射到字段名 CString strField; switch (ColIndex) { case 0: strField _T(name); break; case 1: strField _T(id); break; case 2: strField _T(rate); break; default: return; } // 切换排序方向用成员变量记录当前状态 static BOOL bAsc TRUE; CString strOrder bAsc ? _T( ASC) : _T( DESC); bAsc !bAsc; // 重新查询并绑定 CString strSQL; strSQL.Format(_T(select * from test order by %s%s), strField, strOrder); m_Rs.Close(); m_Rs.Open(strSQL); m_ctrlDG.SetRefDataSource((LPUNKNOWN)m_Rs.GetRecordset()); }逻辑说明每次点击表头先关闭旧记录集再用新的ORDER BY语句重新打开最后重新绑定数据源。static BOOL bAsc用来在升序和降序之间切换实际项目里应该做成成员变量避免多个网格互相干扰。4.3 排序时的界面闪烁与性能问题重新绑定数据源会导致网格重绘数据量大时能看到明显闪烁。缓解办法是在重查前先SetRedraw(FALSE)绑定完再SetRedraw(TRUE)并Refreshm_ctrlDG.SetRedraw(FALSE); // ... 重新查询和绑定 ... m_ctrlDG.SetRedraw(TRUE); m_ctrlDG.Refresh();如果记录超过几千条建议在 SQL 里加TOP限制或者做分页DataGrid 本身不是虚拟列表全量加载会拖慢对话框响应。5. 避坑与排查DataGrid 用不好多半是这几个原因5.1 控件插入后类向导里找不到 CDataGrid现象在对话框上放了 DataGrid 控件但「添加类」时列表里没有CDataGrid、CColumns、CColumn。原因插入控件时选的是「Microsoft DataGrid OLEDB 6.0」但类向导只列出了部分接口或者控件注册表信息不完整。解决重新走一遍「项目 → 添加类 → ActiveX 控件中的 MFC 类」在列表里找到Microsoft DataGrid Control 6.0 (OLEDB)把CDataGrid、CColumns、CColumn三个都勾上。如果列表里根本没有这个控件说明系统没注册MSDATGRD.OCX需要用regsvr32注册。5.2 SetRefDataSource 之后网格空白现象代码没报错但网格里一行数据都不显示。原因最常见的是记录集已经关闭或超出作用域。SetRefDataSource只是传递接口指针DataGrid 不会复制数据如果m_Rs在函数返回后被析构网格就空了。解决把CADODatabase和CADORecordset定义为对话框类的成员变量保证生命周期覆盖整个对话框。另外检查Open的返回值SQL 写错时记录集是空的但不会抛异常。5.3 列宽设置无效或列索引错位现象调了SetWidth但列宽没变或者改完表结构后设置的列跟预期对不上。原因GetItem的 VARIANT 参数类型不对或者 SQL 用了select *导致字段顺序变化。解决VARIANT 显式设vt VT_I2或VT_I4SQL 里把字段名写全比如select name, id, rate from test这样列索引跟字段顺序稳定对应。5.4 百分数格式显示成原值现象设了SetNumberFormat(_T(0.0%))但单元格里还是0.156而不是15.6%。原因字段在数据库里的类型是文本不是数字。DataGrid 对文本字段忽略数字格式。解决检查表结构把该字段改成Single或Double类型。如果数据库不能改只能在 SQL 里用FORMAT函数预处理或者绑定时用计算字段。5.5 表头点击没反应现象写了OnHeadClickDatagrid1但点击表头不触发。原因事件映射的调度 ID 写错或者控件属性里HeadClick事件被禁用。解决用类向导重新生成事件映射确认ON_EVENT的第三个参数跟控件类型库一致。另外检查 DataGrid 的AllowUpdate属性某些版本下该属性为False时事件不派发。6. 一个被忽略的调试习惯用方法名反推控件能力项目正文结尾提到「查看相关类的方法名能顾名思义」这句话我一开始没当回事后来发现是快速上手 ActiveX 控件的捷径。CDataGrid、CColumns、CColumn这三个类的方法名基本就是控件功能的英文直译比如SetHeadFont设表头字体、SetBackColor设背景色、SetColAlignment设列对齐方式。遇到没文档的功能直接在类视图里展开方法列表比翻帮助文件快得多。我现在的习惯是拿到一个不熟悉的 ActiveX 控件先把它生成的封装类头文件打开把所有Set开头的方法扫一遍记下哪些属性可以运行时改。然后写一个临时的「属性遍历」按钮把常用属性挨个设一遍看效果。比如下面这段代码一次性把表头、网格线、选中行颜色都调一遍// 表头背景色和字体 m_ctrlDG.SetHeadBackColor(RGB(0, 120, 215)); m_ctrlDG.SetHeadForeColor(RGB(255, 255, 255)); m_ctrlDG.SetHeadFont(_T(微软雅黑), 10, TRUE); // 网格线颜色 m_ctrlDG.SetGridLineColor(RGB(200, 200, 200)); // 选中行高亮 m_ctrlDG.SetSelBackColor(RGB(255, 240, 200)); // 禁止用户拖动列宽只读展示时有用 m_ctrlDG.SetAllowColResize(FALSE);参数说明SetHeadFont的三个参数分别是字体名、字号、是否加粗颜色值用RGB宏生成COLORREF。这些属性在对话框OnInitDialog里设置一次即可不需要每次刷新都调。还有一个验证技巧DataGrid 绑定记录集后如果想知道当前实际有多少列、列标题是什么可以用CColumns的GetCount和CColumn的GetCaption遍历打印CColumns cols m_ctrlDG.GetColumns(); long n cols.GetCount(); for (long i 0; i n; i) { VARIANT vt; vt.vt VT_I4; vt.lVal i; CColumn col cols.GetItem(vt); CString strCaption col.GetCaption(); TRACE(_T(列 %d 标题: %s\n), i, strCaption); }TRACE输出到调试窗口不用弹对话框就能确认列信息。从那以后我每次接手带 DataGrid 的老项目都强制先跑一遍列信息遍历确认字段顺序和标题再动格式和排序的代码。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Python中使用封装类还是函数以及它们的区别

Python中使用封装类还是函数以及它们的区别

前言 "该用类还是用函数"是写 Python 时绕不开的选择。一句话概括:函数封装的是 "行为",类封装的是"状态 一组操作状态的行为"。 如果一件事只是一次输入到 一次输出的变换,函数就够了;如果一件事…

2026/10/13 11:24:41 阅读更多 →
美国商标专利注册选哪家?真正靠谱的关键只有一个

美国商标专利注册选哪家?真正靠谱的关键只有一个

这个标题看起来简单,但问的人特别多。直接回答: 美国商标专利注册没有“哪个机构好”这种选择题,因为唯一有法律效力的注册机构只有一个:美国专利商标局(USPTO) 。所有“代理机构”“律师事务所”“网络平…

2026/10/13 11:24:41 阅读更多 →
家庭WiFi卡顿?用WiFi Explorer Pro扫描信道与干扰,优化路由器设置

家庭WiFi卡顿?用WiFi Explorer Pro扫描信道与干扰,优化路由器设置

家里那台路由器已经用了三年,指示灯永远绿油油的,但实际体验完全不是那么回事。晚上八点以后,客厅电视盒子放流媒体视频卡成PPT,卧室里手机明明显示信号满格,视频通话还是会频繁掉线。这种场景很多家庭都经历过&#x…

2026/10/13 11:24:41 阅读更多 →

最新新闻

AI芯片软硬件协同设计:架构、编译器与运行时系统全解析

AI芯片软硬件协同设计:架构、编译器与运行时系统全解析

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

2026/10/13 12:07:56 阅读更多 →
AI日报制作指南:选题筛选、信源核验与内容运营

AI日报制作指南:选题筛选、信源核验与内容运营

做AI日报做到现在,我最深的感受是:AI圈从来不缺新闻,缺的是让人愿意看下去的整理方式。每天早上一睁眼,消息群里已经堆了几十条“重磅”“炸场”“史诗级更新”,但真正打开看,有一半是把旧闻改了标题&#…

2026/10/13 12:07:56 阅读更多 →
SpringBoot+Vue影院购票系统开发全解析:数据库设计、并发选座与部署实操

SpringBoot+Vue影院购票系统开发全解析:数据库设计、并发选座与部署实操

做毕设或者想练全栈的同学,在搜索引擎里肯定会刷到一类标题特别标准化的项目:某某影院购票管理系统、某某酒店预订系统、某某校园二手平台。前半段是一个具体业务场景,后半段固定是SpringBootVueMyBatisMySQL,再加一句“完整源码部…

2026/10/13 12:07:56 阅读更多 →
Windows共享打印机连不上?五层服务链修复指南

Windows共享打印机连不上?五层服务链修复指南

简介:这是一款专为Windows系统管理员及IT运维人员设计的共享打印机故障修复工具集,聚焦解决企业环境中常见的打印服务异常、连接失败、驱动丢失及Spooler服务崩溃等问题。资源包含22个文件,以8个批处理脚本(.bat)为核心…

2026/10/13 12:07:56 阅读更多 →
大白菜U盘启动工具v4.6:BIOS/UEFI双模启动盘制作指南

大白菜U盘启动工具v4.6:BIOS/UEFI双模启动盘制作指南

简介:大白菜U盘启动制作工具v4.6新年特别版是一款面向系统维护人员、装机工程师及IT爱好者的专业级启动U盘制作软件,专为解决多场景系统安装、硬盘修复与PE环境定制需求而设计。资源包共2个文件:核心可执行程序(.exe)用…

2026/10/13 12:07:56 阅读更多 →
网络安全体系方法论:可测量、可演进、可归因的实战框架

网络安全体系方法论:可测量、可演进、可归因的实战框架

简介:本资源是一份面向企业安全建设者、IT管理者及网络安全从业者的体系化方法论文档,聚焦解决‘如何构建与业务深度融合的可持续网络安全能力’这一核心问题。文档系统阐述了以IPDRR模型(识别、防护、检测、响应、恢复)为骨架的企…

2026/10/13 12:06:53 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 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/12 21:05:09 阅读更多 →
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/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →