VC++ MFC开发企业级MIS系统:现代重构与性能优化实战
1. 项目概述为什么选择VC MFC在202X年开发MIS如果你在202X年听到有人用VC MFC开发一个全新的管理信息系统MIS第一反应可能是“这技术栈是不是有点老了” 我半年前启动这个项目时身边不少朋友也这么问。但历时半年当我交付了一个界面炫酷、运行稳定、功能强大的MIS客户端后他们才明白技术栈的“新”与“旧”从来不是绝对的关键在于是否“合适”。这个项目是为一家制造业企业定制的内部生产与物料管理系统核心需求是在Windows环境下稳定高效运行、与大量遗留的COM组件和ActiveX控件无缝集成、拥有复杂的自定义数据网格和报表打印功能并且客户端部署要极其简单。在评估了Qt、WinForms、WPF甚至Electron之后我最终还是回到了VC MFC。原因很直接零依赖部署、与Windows系统深度集成、对复杂界面控件的极致性能控制以及最重要的——与现有C业务逻辑库的无缝对接。MFC虽然“古老”但其基于C的框架在性能密集型、界面逻辑复杂的桌面应用领域尤其是需要深度定制UI和与底层硬件或专有协议打交道的场景下依然有着不可替代的优势。这半年的实战更像是一次对经典技术的深度挖掘与现代重构证明了老技术栈在特定需求下依然能焕发出强大的生产力。2. 核心架构设计与技术选型考量2.1 现代Visual Studio环境下的MFC项目配置很多人对MFC的印象还停留在Visual Studio 6.0时代这是一个巨大的误解。我使用的是Visual Studio 2022它提供了对MFC项目完整且现代化的支持。新建项目时选择“MFC应用程序”向导会提供多种应用类型单文档、多文档、对话框基于。对于MIS这类数据密集型应用我选择了**“基于对话框”** 的应用类型并将其作为主容器内部通过Tab Control或自定义的Pane来管理各个功能模块。这样做的灵活性远高于传统的文档/视图架构。注意在VS2022中创建MFC项目时务必在“应用程序类型”中勾选“使用Unicode库”这是现代Windows应用的基石。同时在“高级功能”中建议勾选“公共控件清单”以确保控件样式是现代风格以及“支持重新启动管理器”以增强应用健壮性。一个关键决策是静态链接MFC库还是动态链接。为了达成“零依赖部署”的目标我选择了静态链接/MT或/MTd。这意味着最终生成的单个EXE文件可以在任何干净的Windows 10/11系统上直接运行无需安装任何VC运行库。代价是EXE文件体积会增大大约增加几MB但对于内部系统部署而言这个代价完全可以接受它彻底避免了用户机器上运行库版本冲突的噩梦。2.2 界面现代化告别“灰盒子”拥抱现代UIMFC默认的界面风格确实是90年代的“灰盒子”风格但这绝不意味着我们做不出炫酷的界面。我的核心思路是以原生控件为基础通过自绘Owner Draw、自定义控件和第三方UI库进行深度美化。换肤引擎的引入我选择了BCGControlBar Pro这个老牌且强大的MFC扩展库。它提供了大量现代化的控件如Ribbon界面、Office风格按钮、视觉管理器等。通过BCG我可以轻松实现应用程序整体换肤从Office 2007到Visual Studio 2019的深色主题都能一键切换。这为“界面炫酷”打下了坚实基础。列表控件的彻底改造MIS的核心是数据展示CListCtrl是主力。但原生的CListCtrl功能简陋。我的做法是使用虚拟列表LVS_OWNERDATA对于可能显示上万条记录的数据网格启用虚拟模式。控件只请求当前可见区域的数据由我们通过LVN_GETDISPINFO通知消息来提供内存占用极低滚动流畅。完全自绘Custom Draw响应NM_CUSTOMDRAW消息我可以精确控制每一行、每一列、每一个单元格的背景色、文字颜色、字体。实现了斑马纹、行高亮、条件着色如超期订单标红等效果。嵌入复杂控件在单元格内嵌入组合框CComboBox、日期时间选择器CDateTimeCtrl甚至按钮实现原地编辑。这需要处理LVN_BEGINLABELEDIT和LVN_ENDLABELEDIT并在适当位置创建和显示这些子控件。非客户区美化通过重写OnNcPaint、OnNcCalcSize等消息自定义了窗体的标题栏、边框和阴影效果使其更符合现代扁平化设计风格。2.3 数据层设计高效、清晰、可维护MIS的核心是数据处理。我采用了典型的分层架构但在MFC的上下文中进行了具体化视图层View即对话框和各类控件只负责数据的展示和用户交互事件的捕获。它通过调用控制器Controller的接口来发起业务请求。控制器层Controller这是业务逻辑的核心。我创建了一系列的C管理器类如CUserManager、COrderManager、CReportManager等。它们负责处理具体的业务规则、数据验证和流程控制。数据访问层DAO为了与数据库交互我没有使用古老的CDatabase而是采用了ODBC 原生SQL的方式封装了一个轻量级的CDBHelper类。它封装了连接池管理、参数化查询防止SQL注入、事务处理等。对于简单的ORM映射我手动编写了实体类如CUserInfo、CProduct并在DAO类中实现LoadFromResultSet和ToStatementParams这类方法虽然不如全功能ORM方便但胜在绝对可控和高性能。// 示例一个简单的数据实体和DAO操作 class CProduct { public: int m_nID; CString m_strName; double m_dPrice; // ... 其他字段 }; class CProductDAO { public: BOOL LoadProduct(int nID, CProduct product) { CDBHelper db; // 使用参数化查询 db.PrepareStatement(_T(SELECT id, name, price FROM products WHERE id ?)); db.SetParameter(1, nID); if (db.ExecuteQuery() db.Next()) { product.m_nID db.GetIntValue(0); product.m_strName db.GetStringValue(1); product.m_dPrice db.GetDoubleValue(2); return TRUE; } return FALSE; } // ... 增删改查其他方法 };3. 关键功能模块的深度实现与炫酷效果打造3.1 动态仪表盘与图表集成主界面需要一个直观展示KPI的仪表盘。我使用了TeeChart的ActiveX控件。在MFC中集成ActiveX控件非常方便通过“工具 - 选择工具箱项 - COM组件”勾选TeeChart控件它就会出现在工具箱里拖到对话框上即可。通过其丰富的接口可以动态生成柱状图、折线图、饼图来展示销售额、库存预警、生产进度等关键指标。为了让图表区域与整体UI风格融合我将其嵌入到一个自定义的CPane中并重写OnEraseBkgnd绘制渐变色背景使图表看起来像是应用原生的一部分而不是一个突兀的“外来户”。3.2 多线程与后台任务处理MIS中经常有数据导出、报表生成、批量打印等耗时操作。绝不能阻塞UI线程。我广泛使用了工作线程Worker Thread结合消息通知的模式。创建工作者线程使用AfxBeginThread创建一个后台线程函数。线程安全通信通过向主线程窗口发送自定义消息WM_USER XXX来传递进度、状态和完成信号。传递复杂数据时需要动态分配内存如new一个结构体并通过消息的WPARAM或LPARAM传递指针在消息处理函数中处理后务必记得删除防止内存泄漏。UI进度反馈在对话框上放置一个CProgressCtrl并启用PBS_MARQUEE风格滚动条表示后台任务进行中。通过线程发送的进度消息来更新进度条的具体数值或状态文本。实操心得在MFC中从非UI线程直接调用UI控件的方法如SetWindowText是危险的可能导致崩溃。必须使用PostMessage或SendMessage将操作派发到UI线程的消息队列中执行。我封装了一个PostUIMessage的辅助函数来简化这个操作。3.3 快捷键与自定义菜单/工具栏为了提高操作效率完善的快捷键支持必不可少。MFC框架本身对加速键表Accelerator有很好的支持。编辑资源文件中的加速键表在资源视图里可以直观地添加快捷键如CtrlN对应ID_FILE_NEW。对话框中的快捷键处理对于基于对话框的应用需要手动加载加速键表并在PreTranslateMessage函数中调用TranslateAccelerator。更灵活的方式是重写PreTranslateMessage直接检查pMsg针对特定控件或状态进行快捷键响应。动态菜单/工具栏根据用户权限动态启用或禁用某些菜单项和工具栏按钮。这通过在UPDATE_COMMAND_UI消息处理函数中调用pCmdUI-Enable()来实现。例如只有管理员才能看到“用户管理”菜单。// 在CXXXDlg::PreTranslateMessage中处理对话框快捷键 BOOL CProductManageDlg::PreTranslateMessage(MSG* pMsg) { if (pMsg-message WM_KEYDOWN) { if (GetKeyState(VK_CONTROL) 0) { // Ctrl键按下 switch (pMsg-wParam) { case F: // CtrlF 快速查找 OnBnClickedButtonSearch(); return TRUE; case N: // CtrlN 新增 OnBnClickedButtonNew(); return TRUE; } } if (pMsg-wParam VK_F5) { // F5 刷新 RefreshProductList(); return TRUE; } } return CDialogEx::PreTranslateMessage(pMsg); }3.4 报表生成与打印报表是MIS的硬需求。我放弃了陈旧的Crystal Reports选择了FastReport或Stimulsoft Reports这类支持本地化集成且功能强大的报表库。它们通常提供COM或原生DLL接口。实现步骤设计报表模板.frx文件在报表设计器中设计好格式。集成报表引擎将报表库的头文件和lib/dll文件引入项目。数据绑定在代码中加载模板将数据集通常是一个Recordset或自定义的数据结构传递给报表引擎。预览与打印调用引擎的预览对话框或直接发送到打印机。我实现了一个自定义的打印预览对话框嵌入了报表的预览控件使其与应用风格一致。对于简单的列表打印我仍然使用了MFC的CDC打印功能。通过重写OnPrint可以精确控制每一页的绘制内容实现分页、页眉页脚、表格线等。虽然代码量稍大但灵活性最高且不依赖第三方组件。4. 开发过程中的疑难杂症与性能优化实录4.1 内存泄漏排查必备工具VLDC开发最怕内存泄漏。在MFC中如果误用了new/delete或者MFC自身的对象如CDC*未正确释放泄漏就会发生。我强烈推荐在调试版本中集成Visual Leak Detector。只需包含头文件#include vld.h并在程序退出时VLD会在输出窗口打印出完整的泄漏堆栈信息精确到文件和行号是定位泄漏点的神器。4.2 GDI对象泄漏一个隐蔽的坑另一个常见问题是GDI对象泄漏画笔、画刷、字体、位图等。Windows系统对每个进程的GDI对象数量有限制约10000个。如果频繁创建CPen,CBrush而未删除会导致程序运行一段时间后界面卡死或崩溃。避坑技巧遵循“谁创建谁删除”的原则。对于在OnPaint等函数中临时创建的GDI对象使用CPen pen(PS_SOLID, 1, RGB(0,0,0))这样的栈对象函数结束时会自动调用析构函数释放。如果必须动态创建new CPen则务必在不再使用时delete它。更优雅的方式是利用MFC的CGdiObject派生类的特性使用Attach/Detach来管理已有的GDI句柄。4.3 列表控件CListCtrl虚拟模式下的性能陷阱使用虚拟列表LVS_OWNERDATA时LVN_GETDISPINFO消息会频繁触发。如果在这个消息的处理函数中进行复杂的数据库查询或计算将导致滚动时严重卡顿。解决方案建立一个内存缓存。在数据加载时将当前视图所需的数据比如前后多缓冲几百条预先加载到一个std::vector或CArray中。当LVN_GETDISPINFO触发时直接从缓存中返回数据速度极快。同时开启一个后台线程监听滚动位置的变化异步预加载即将进入视图的数据到缓存中。4.4 解决编辑框CEdit与数字输入的烦恼MIS中大量输入数字的场合。MFC的CEdit默认接收所有字符。为了限制只能输入数字、小数点或负号传统做法是继承CEdit重写OnChar。但我发现一个更简洁的方法使用消息反射。在对话框类中处理WM_CHAR消息判断当前焦点控件是否为需要限制的编辑框然后过滤字符。或者直接使用DDX_Text并配合DDV_MinMaxDouble等验证宏虽然简单但提示不够即时。我最终的方案是为数字输入专门封装一个CNumEdit类它继承自CEdit内部处理WM_CHAR和WM_PASTE粘贴并提供一个GetValue/SetValue的接口直接返回double或int类型极大简化了业务代码。4.5 多语言国际化支持的实现虽然本项目是内部系统但考虑到未来可能我预留了多语言支持。MFC本身通过资源DLL.dll支持多语言。我的做法是将所有界面字符串CString、对话框标题、菜单文本等都定义在资源文件.rc的STRINGTABLE或控件属性中。使用Visual Studio的“资源编辑器”为每种语言如中文、英文创建单独的资源副本。在程序启动时根据系统语言或用户设置动态加载对应语言的资源DLL使用AfxSetResourceHandle。对于动态生成的字符串如“共%d条记录”使用CString::Format配合从资源文件加载的格式字符串。5. 部署与维护打造企业级健壮性5.1 生成调试信息与崩溃报告用户环境千差万别程序难免崩溃。为了能远程定位问题必须生成详细的调试信息。生成PDB文件在项目属性 - “链接器” - “调试”中确保“生成调试信息”为“是”并选择“生成程序数据库文件/DEBUG”。集成崩溃报告我使用了开源库CrashRpt。将其集成到项目中后它能自动捕获未处理的异常如访问违规、除零错误生成一个包含调用堆栈、寄存器状态、屏幕截图等信息的迷你转储文件.dmp并可以提示用户发送错误报告。这比让用户描述“点了哪里就闪退了”要高效一万倍。5.2 打包与一键安装即使我们静态链接了MFC有时仍需要确保目标机器上存在必要的系统组件如特定版本的Windows通用C运行时。我使用Inno Setup作为安装包制作工具。它的脚本强大且免费。在安装脚本中可以检测系统环境必要时静默安装VC运行库尽管我们静态链接但有时为其他依赖准备、.NET Framework如果用了某些混合组件等。最终打包成一个单一的setup.exe用户双击即可完成安装所有快捷方式、文件关联、注册表项一并配置好。5.3 日志系统程序的“黑匣子”一个健壮的企业应用离不开日志。我实现了一个简单的异步日志类CLogger。它内部有一个生产者-消费者队列。所有写日志的请求如LOG_INFO(“用户%s登录成功”, userName)都被放入队列由一个单独的日志线程负责取出并写入文件。这样做避免了磁盘IO操作阻塞主线程。日志文件按日期滚动如AppLog_20231027.log并支持不同的日志级别DEBUG, INFO, WARN, ERROR在发布版本中可以关闭DEBUG级别以减少IO。6. 对新手开发者的建议与避坑指南如果你也打算用VC MFC开发类似项目以下是我半年踩坑后的肺腑之言拥抱现代C不要局限于MFC那套宏和风格。在业务逻辑层大胆使用std::vector,std::map,std::string(或CStringA),std::thread,std::mutex等现代C标准库组件。它们比MFC的CArray,CMap,CString在某些场景下更安全、更高效。MFC主要用于UI层。善用第三方库不要试图用原生MFC重造所有轮子。对于UI美化BCGControlBar或Codejock Xtreme Toolkit是值得投资的。对于图表TeeChart或Highcharts的本地封装是不错的选择。对于JSON解析使用nlohmann/json对于网络通信可以考虑libcurl。用合适的工具做合适的事。理解消息机制MFC的核心是消息映射。一定要花时间理解PreTranslateMessage、WindowProc、消息反射、命令路由ON_COMMAND和ON_UPDATE_COMMAND_UI的机制。这是解决很多界面交互诡异问题的钥匙。资源管理是重中之重牢记new/delete配对善用智能指针如std::unique_ptr管理非MFC对象。对于MFC的GUI对象如CWnd派生类理解DestroyWindow和析构函数的关系。使用VLD定期检查。调试是常态熟练使用Visual Studio的调试器条件断点、内存监视、调用堆栈查看是基本功。对于界面布局问题SpyVisual Studio自带工具是神器可以查看任何窗口的句柄、类名、样式和消息。历时半年的项目已经上线稳定运行用户对流畅的体验和专业的界面反馈积极。这个项目让我深刻体会到没有过时的技术只有不合适的使用场景。VC MFC这套“老枪”在精心打磨和结合现代开发实践后依然能在企业级桌面应用开发中担当大任尤其是在性能、稳定性和部署简便性要求极高的领域。它要求开发者对Windows底层和C有更深的理解但带来的控制力和最终成果的“扎实感”是许多快速开发框架难以比拟的。

相关新闻

ResNet残差网络:从网络退化到深度革命的核心原理与实战应用

ResNet残差网络:从网络退化到深度革命的核心原理与实战应用

1. 从“网络退化”到“深度革命”:ResNet的诞生背景 如果你在2015年之前尝试训练一个超过20层的卷积神经网络(CNN),大概率会遇到一个令人沮丧的现象:随着网络层数的增加,模型的训练误差和测试误差不仅没有降…

2026/10/16 2:02:46 阅读更多 →
MCBE极速T触发器设计:基于观察者与活塞的高频红石电路实现

MCBE极速T触发器设计:基于观察者与活塞的高频红石电路实现

在红石电路设计中,我们常常追求更快的响应速度和更高的运行效率。尤其是在一些对时序要求极为苛刻的场合,比如高频脉冲发生器、紧凑型计算单元或极限速通地图中,一个快速、稳定的T触发器(T Flip-Flop)是构建复杂逻辑的…

2026/10/20 5:28:57 阅读更多 →
Go语言实现轻量级高并发物联网数据接收服务

Go语言实现轻量级高并发物联网数据接收服务

1. 项目概述:轻量级高并发物联网数据接收服务在物联网设备爆发式增长的当下,数据接收服务作为终端设备与业务系统间的"第一公里"通道,其性能表现直接影响整个系统的可靠性。这个用Go语言实现的轻量级服务源码,专为解决硬…

2026/10/20 0:44:28 阅读更多 →

最新新闻

spooling假脱机模拟:2请求进程+1输出进程的并发控制与信号量实现

spooling假脱机模拟:2请求进程+1输出进程的并发控制与信号量实现

简介:这份资源围绕操作系统中的Spooling假脱机输入输出模拟技术展开,面向计算机专业学生及系统设计学习者,帮助理解如何通过磁盘缓冲将慢速I/O设备虚拟化,实现多进程共享打印机等外设。包内共11个文件,以5个class编译文…

2026/10/21 2:52:02 阅读更多 →
原生应用接入AI的伦理与合规:从开源许可到隐私边界

原生应用接入AI的伦理与合规:从开源许可到隐私边界

1. 为什么原生应用开发者绕不开“AI伦理”这道门槛“AI伦理”这四个字放在前几年,很多做原生应用开发的同行会觉得这是大厂法务和研究院才需要操心的事。但这两年情况完全不一样了——几乎每个原生应用都在往里面塞AI能力,从刷脸登录、智能客服&#xff…

2026/10/21 2:52:02 阅读更多 →
PowerBuilder 11.5 环境搭建与数据窗口连库实战指南

PowerBuilder 11.5 环境搭建与数据窗口连库实战指南

简介:PowerBuilder 11.5 安装文件资源包,面向需要搭建经典 PB 开发环境的学习者与维护老项目的开发者。PowerBuilder 是 Sybase 推出的快速应用开发工具,11.5 版本在数据窗口、数据库连接与客户端应用开发方面较为成熟,适合用于课…

2026/10/21 2:52:02 阅读更多 →
JSP+Servlet学生管理系统毕设实战指南

JSP+Servlet学生管理系统毕设实战指南

简介:这是一份面向Java Web初学者与高校课程实践者的完整学生信息管理系统教学资源,基于JSP与Servlet技术栈实现MVC分层架构,覆盖动态网页开发、HTTP请求处理、JDBC数据库操作及Tomcat容器部署等核心知识点。资源包共576个文件,包…

2026/10/21 2:52:02 阅读更多 →
MPlayer启用VAAPI硬解:编译、配置与验证实战

MPlayer启用VAAPI硬解:编译、配置与验证实战

手里还有一台老机器,跑着轻量级Linux桌面,平时看本地视频一直用MPlayer的-vo和-slave接口,自动化脚本都绑死在上面。后来换了4K片源,CPU直接拉满,画面一卡一卡的,我才认真考虑给MPlayer接上VAAPI硬解。折腾…

2026/10/21 2:52:02 阅读更多 →
知网AIGC检测原理与降AI工具实测:从标红到通过的完整攻略

知网AIGC检测原理与降AI工具实测:从标红到通过的完整攻略

去年有一阵子,实验室里的几位同学轮流来找我,说同一个问题:初稿明明是自己熬夜搭出来的框架,再用AI润了一轮,结果往知网AIGC检测系统一放,直接标红一片,相似度干到百分之四五十,要求…

2026/10/21 2:51:01 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练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/20 9:50:45 阅读更多 →