news 2026/9/8 3:33:25

MFC地铁查询系统课设全解析:从数据库设计到路径算法与打包发布

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MFC地铁查询系统课设全解析:从数据库设计到路径算法与打包发布

简介:一份基于MFC的南京地铁查询系统完整工程源码,面向自学C++/MFC的开发者,也适合作为课程设计与毕业设计的参考模板。压缩包共43个文件,仅2.44MB,包含h头文件、cpp源文件、rc资源描述、bmp地铁运营示意图、ico图标以及可直接运行的exe和调试符号文件(pdb/obj等),便于对照源代码逐步调试。工程中通过属性页对话框与地图显示对话框组织界面,涉及CDialog/CPropertySheet、消息映射、控件绑定与GDI位图绘制等典型MFC技术;线路查询的核心逻辑集中在主要源文件中,可以清晰地看到程序初始化、对话框交互与查询结果展示的完整流程。已有958人学习/下载,适合希望快速上手Windows桌面应用开发、并希望基于现成框架二次扩展的读者。 最近帮一个学弟把他的课程设计“基于MFC的南京地铁查询系统”从能跑调到能交,前前后后踩了不少坑,也把MFC那套老掉牙但关键时刻真能顶上的控件和画图机制又摸了一遍。这个题目听起来很简单,就是做个地铁线路查询,但真做起来涉及的东西不少:界面布局、数据库存线路站点、最短路径算法、甚至还有打包发布时那堆运行时库的幺蛾子。这篇就把整个项目的设计思路、核心实现、常见坑位一次讲清楚,给正在做类似MFC课设或者想复习传统Win32桌面开发的朋友一个参考。

先说结论:如果你的课设题目带“XX查询系统”,而且指定用MFC,那么本质就是在考察三件事——C++面向对象的基本功、MFC的控件和消息映射机制、以及最简单的那层数据库增删改查。地铁查询系统的难点不在UI也不在数据库,而在换乘路径的计算。苏州、南京、北京这种地铁成网的城市,站点之间的最短路径和最少换乘是图论里最经典的场景,用Dijkstra或者BFS都能搞定,关键是数据结构怎么设计,以及MFC里怎么把计算结果塞给界面去显示。

1. 整体设计与技术选型

1.1 为什么MFC至今仍是课设和部分工业项目的首选

在开始写代码之前,先想一个问题:为什么这个题目指定MFC?现在已经2025年了,Web前端随便拖个组件库都能做得比MFC好看十倍,Python配PyQt也能快速出界面,但MFC依然活在大量课程设计、老旧系统维护、工业上位机项目里,原因就三个:

第一是历史包袱。很多学校和企业积累了大量的MFC代码库,新项目迁到别的框架成本太高。第二是学起来确实能练到C++底层功底,MFC帮你把Win32 API包了一层,但消息映射、句柄管理、指针生命周期这些概念全得自己扛,对理解Windows程序运行机制帮助很大。第三是发布简单,一个exe加几个DLL就能跑,不像Qt动不动几十MB的依赖。

不过说实话,如果你是自己选型做类似项目,我反倒建议考虑Qt或C#,开发效率高得多。但这个题目既然定了MFC,那就得把MFC的脾性摸透,用最合适的方式实现。

我做这个项目时用的是VS2013 + MFC,数据库选的MySQL 5.7,原因是学弟的课设环境就是这么配的。如果你用的是VS2019或VS2022,需要注意MFC的向导生成代码会有细微差异,比如高DPI支持、字符集默认设置不同,但核心开发逻辑完全一样。

1.2 系统功能模块划分

拿到这个题目别急着双击打开VS拖控件,先把功能模块拆清楚。一个南京地铁查询系统,至少要覆盖以下功能:

  • 地铁线路和站点的浏览,比如看到底有哪些线路,每条线经过哪些站
  • 站点信息查询,输入站名能查到它属于哪条线、下一站是哪里
  • 换乘查询,给定起点站和终点站,输出一条合理的乘车路线(经过哪些站、在哪换乘、总共多少站)
  • 数据管理功能(加分项),比如管理员可以增删站点或线路

把这个列出来后你会发现,前两个是纯展示和简单查询,第三个才是核心算法模块。很多人的课设就挂在换乘查询上,因为站点之间不是简单的线性关系,而是网状的图结构。

界面布局我用的是左边的树控件(CTreeCtrl)显示所有线路和站点,右上角是查询条件和按钮,右下角是结果输出的静态文本框或列表控件。这样一层是线路,二层是站点,点任何一个站点都能在文本框显示详细信息,逻辑很清晰。

提示:功能拆分一定要写进课设报告里,这个模块划分图即使画得再丑,老师也会觉得你思路清楚。哪怕最后只实现了部分功能,报告里的模块结构也要完整,这是加分项。

2. 数据库设计与核心算法

2.1 表结构设计:别把关系数据库当文本文件用

数据库是整个系统的数据底座。南京地铁的站点和线路数据不算大,总共也就十几条线两三百个站,完全可以用更轻量的文件存储方式,但课设题目既然写了“系统”,数据库是标配,而且答辩时老师大概率会问表怎么设计的。

我的表结构设计成三张表,规范化程度适中,好查也好写。

第一张是line线路表,字段很简单:

  • line_id主键,自增
  • line_name线路名,比如“1号线”“S1号线”
  • line_color线路颜色,这个非常重要,因为后面画线路图或做界面展示时要用颜色区分线路

第二张是station站点表:

  • station_id主键,自增
  • station_name站点名,比如“新街口”“南京南站”
  • interchange_flag是否换乘站,这个字段可以不在数据库里存,通过业务逻辑判断,但存了之后查询会快很多,课设规模无所谓,但报告里写“冗余设计以空间换时间”很加分

第三张是关键的表line_station线路站点关系表,用于描述“某条线路经过哪些站点,顺序是什么”:

  • id主键自增
  • line_id线路ID,关联line表
  • station_id站点ID,关联station表
  • station_order站点在该线路上的顺序号,从1开始递增

这三张表的结构非常经典,也是真实地铁线路数据库设计的原型。很多同学会想省事,只建一张表把每条线的站点用逗号拼在一起,也能实现功能,但换乘查询和路径计算会变得极其痛苦。数据规范化虽然要多写几条SQL,但后面的代码会简单十倍。

注意:station_order这个字段是灵魂,没有它你就没法知道线路方向,不知道方向就没法计算“坐几站”。

2.2 换乘查询的核心:BFS和Dijkstra都需要先建图

换乘查询本质上是一个图的最短路径问题。南京地铁的每个站是一个节点,如果两个站属于同一条线而且是相邻站,那它们之间就有一条边,边的权重可以设为1(站数)或者设为换乘时的额外时间惩罚。

对课设来说,我建议用BFS广度优先搜索而不是Dijkstra,原因有两个:第一,如果所有边的权重都是1,BFS就能找到最短路,不需要引入优先队列;第二,BFS的代码量比Dijkstra少得多,而且写起来直观,方便在报告里解释。不过如果你想让系统“看起来更高级”,可以用Dijkstra并给换乘边加权重,比如换乘一次加5分钟,然后求总时间最短路径。这个优化能让答辩老师眼前一亮。

建图的过程是这样的:从数据库加载所有线路和站点,构建两个映射容器。第一个是map<string, int>把站点名映射到节点编号,第二个是vector<vector<int>>vector<set<int>>表示邻接表。每读取line_station表里的相邻两条记录,就在两个站点之间加一条无向边。

BFS算法的实现我用了标准库的queue。队列初始放入起点站编号,用一个vector<int>数组记录每个节点的前驱节点,这样回溯时就能得到完整路径。如果走到终点就直接跳出,此时前驱数组中记录的就是一条最短路。因为BFS是逐层扩展的,首次到达终点的路径一定是最短路径。

换乘信息怎么提取?路径得到之后,遍历路径上的每个节点,如果某个节点同时属于两条或以上线路,说明这里可以换乘。但这里有个细节:一个换乘站可能连接多条线路,实际坐车时乘客可能不需要换乘也经过这个站,比如新街口是1号线和2号线换乘站,但你从珠江路坐到张府园,也会经过新街口,这时不需要换乘提醒。所以提取换乘点时要看路径中该站之前和之后分别属于哪条线,如果前一段和后一段线路ID不同,才需要换乘。

// 核心函数:根据前驱数组回溯并生成换乘点集合 void GenerateRoute(int startIdx, int endIdx, const vector<int>& parent, const vector<StationInfo>& stations, vector<RoutePath>& paths) { vector<int> route; for (int cur = endIdx; cur != -1; cur = parent[cur]) { route.push_back(cur); } reverse(route.begin(), route.end()); int currentLine = -1; for (size_t i = 0; i < route.size(); i++) { int lineId = stations[route[i]].lineId; if (i == 0 || lineId != currentLine) { // 记录换乘点或者起点 paths.emplace_back(RoutePath{route[i], lineId, currentLine}); currentLine = lineId; } } }

上面这段代码是一个简化版本,实际项目中站点信息要更复杂一些,需要从数据库加载每个站点与线路的对应关系。但思路就是这样:先找出路径中的线路切换点,然后在这些位置生成换乘提示。

3. 关键功能的代码实现

3.1 MFC中连接MySQL的正确姿势

MFC连接MySQL的方式有很多种,常见的是用ODBC、MySQL Connector/C++,或者直接用最原始的MySQL C API。课设建议用MySQL C API,因为配置最简单:在VS里把MySQL安装目录下的include和lib路径加进来,链接libmysql.lib,然后include<mysql.h>就能用了。

但这里面有几个坑,第一个就是字符集问题。MFC程序默认用的字符集是Unicode,也就是所有CString内部是宽字符wchar_t,而MySQL的C API接口默认用的是UTF-8或gbk的单字节字符集。如果你直接通过mysql_query()执行中文SQL,从MySQL取回来的中文字段是乱码的。千万别试图用CString直接转char*,因为CString在Unicode编码下转出来的char*根本不是UTF-8。

我最终的解决方案是:所有数据库操作全部走UTF-8编码。在连接数据库后先执行mysql_query(mysql, "SET NAMES UTF8MB4"),然后程序内部所有需要传给MySQL的CString,用CW2A转换宏把宽字符转成UTF-8的char*。从MySQL取回来的是UTF-8编码的字符串,用CA2W转成宽字符给界面显示。这一步搞定了,整个系统的中文显示就再也不用操心了。

// 连接数据库的初始化代码 void CDBManager::Connect() { mysql_init(&m_mysql); if (!mysql_real_connect(&m_mysql, "localhost", "root", "123456", "nanjing_metro", 3306, NULL, CLIENT_MULTI_STATEMENTS)) { AfxMessageBox(_T("数据库连接失败!")); return; } // 统一使用UTF-8编码,避免中文乱码 mysql_query(&m_mysql, "SET NAMES UTF8MB4"); } // CString转UTF-8 CStringA Utf8FromCString(const CString& str) { int len = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); char* buf = new char[len]; WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, len, NULL, NULL); CStringA result(buf); delete[] buf; return result; }

第二个坑是VS2013的“字符集”设置。MFC工程创建时向导会让你选“使用Unicode字符集”还是“使用多字节字符集”,虽然现在新项目都默认Unicode,但网上下载的旧项目很多是多字节。如果你用的是多字节模式,很多宽字符函数都要改成单字节版本,麻烦得很。建议创建工程时直接选Unicode,然后所有界面字符串都用_T()宏包裹,这样切换字符集时不用改代码。

3.2 列表框控件使用:显示查询结果的最佳选择

MFC里的CListBox(列表框)是显示线路查询结果的利器。你可以用CListBox::AddString()往里面添加字符串,用CListBox::ResetContent()清空已有内容。它比CEdit更适合展示多条数据。

但默认的CListBox只能显示单列,而且不能调整列宽,对地铁系统这种“每条查询结果都是一个包含多字段的字符串”来说足够了,只要你自己拼好格式。比列表控件CListCtrl轻量得多。

我的实现思路是:用户输入起点站和终点站后,点击查询按钮,系统先调算法计算路径,然后把路径上的每个站点都包装成一条字符串,格式类似“第1站: 新街口 (1号线)”,依次添加到CListBox里。如果用户只输入了单个站点名,则查询该站点所在的所有线路信息,每一行显示一条线路及它在线上是第几站。

如果你想让界面更美观,可以用CListCtrl列表视图控件,设置成Report模式,添加三列:序号、站名、所属线路。这样看起来就像一张表格,老师看了也觉得专业。但CListCtrl的操作比CListBox复杂一些,要先设置列头再插入行,而且插入时要手动管理Item的状态,对初学者不太友好。我建议先保证功能,然后在时间充裕的情况下再升级,把CListBox替换成CListCtrl

3.3 静态文本覆盖问题:自定义控件的起点

你可能在网上看到“MFC静态文本 覆盖”这个热搜词,这说的是一个很经典的问题:MFC的CStatic控件不支持背景透明,如果要在它上面叠加其他控件或者绘制内容,就会出现文字被背景挡住的“覆盖”现象。

地铁查询系统的界面上,我需要在背景图上叠一层文字,显示当前选中的站点信息。直接用CStatic会发现在运行时背景是灰色的,完全破坏视觉。解决办法是把静态文本控件的SS_NOTIFY风格打开,然后重写OnCtlColor,让静态文本的背景色变成和父窗口一样。有些资料说可以通过SetBkMode(TRANSPARENT)让背景透明,实测下来在MFC里直接操作CDC设透明背景,会导致文字叠影、刷新闪烁,体验很差。

实操经验:如果你只是想让某个静态文本和父窗口背景一色,最简单的方式是在OnCtlColor里处理,而不是OnEraseBkgnd。这个做法的本质是告诉Windows“这个控件的背景我自己画”,而不是用默认的灰色。文字有重影就去掉CStaticSS_SUNKEN风格,那个风格自带边框和阴影。

4. 界面美化与绘图细节

4.1 自定义按钮:三步实现圆角高光效果

MFC自带的CButton长得很丑,默认风格是上世纪九十年代的灰色方块,和现代审美完全不搭。网上搜“MFC自定义按钮”,实际就三步:继承CButton写一个子类,重写DrawItem虚函数,再给按钮设置BS_OWNERDRAW自绘风格。

第一步,写一个CMyButton类,继承CButton。第二步,在DrawItem里用CDC类绘制按钮的外观,比如画个圆角矩形、填充渐变、根据按钮状态(按下、悬停、禁用)切换颜色。第三步,在对话框模板里或者动态创建时给按钮设置BS_OWNERDRAW标志。

这个自绘按钮实现起来不难,真正难的是画圆角矩形时对CDC::RoundRect的用法不熟悉,导致圆角半径变成了矩形一半变成圆形,或者边框画出来不均匀。我的建议是,用CRect定义一个内缩2像素的矩形,然后调用RoundRect(rect, CPoint(8, 8))固定圆角半径8像素,这样看起来最自然。

自定义按钮做完之后,系统界面瞬间脱离课设感。老师对界面印象分提高,答辩时也可以说“我扩展了MFC的控件体系,实现了自绘按钮”,这是一个非常亮眼的加分点。

4.2 在MFC中画一个彩色正方形:GDI绘图基础

“基于MFC绘制一个彩色正方形”是网上常见的学习示例,它背后的正式内容是GDI(图形设备接口)。地铁查询系统的线路图如果不想用图片素材,可以直接用GDI画出来,动态绘制站点和线路。

实现方式是在对话框的OnPaint函数里获取CPaintDC,利用CDC::MoveToCDC::LineTo画线,用CDC::RectangleEllipse画站点圆圈。如果要给正方形填充颜色,用CBrush对象,传入RGB()宏,然后调用CDC::FillRectSelectObject选入画刷。

如果你想让线路图支持鼠标拖动、放大缩小,就需要在OnMouseMove里处理坐标变换,把逻辑坐标和屏幕坐标做映射。课设阶段做一个静态的、固定坐标的线路图就够了,拖拽缩放是加分的表演项。但我实测下来,如果时间不充裕,不要轻易加拖拽缩放,因为MFC的绘图重绘机制会让你处理大量的消息,而且双缓冲没做好的话界面会闪烁得像霓虹灯。

4.3 双缓冲绘图:告别闪烁的秘诀

画地铁线路图时,如果直接在OnPaint里往屏幕DC上画,窗口一刷新整个图就闪得不行。原因是每次重绘时先擦掉背景再慢慢画新内容,人眼能明显看到这个过程。

解决方法就是双缓冲(Double Buffering):先创建一个和窗口DC兼容的内存DC和位图,把所有图形画到内存DC里,最后一次性BitBlt到屏幕DC。这个操作在GDI编程里是基本素养,在MFC里可以通过CDC memDC; memDC.CreateCompatibleDC(pDC);配合CBitmap实现。

我在地铁系统里用双缓冲画线路图,站点多的时候拖动窗口也完全不闪。这个技术点老师很可能在答辩时问你,公式就是三段:创建内存DC -> 画图 -> 一次性拷贝。

5. 打包发布与常见问题排查

5.1 MFC项目如何打包:既要能跑又要小

课设交完后往往要交一个能直接运行的演示程序,这就涉及到MFC项目打包。MFC程序打包的核心问题就是运行时库。MFC默认是动态链接到mfc140u.dll(VS2015及以后)或mfc120u.dll(VS2013)这类动态库,如果目标机器上没有这些DLL,程序一打开就报0xc000007b或者“缺少mfc120u.dll”。

最简单粗暴的方式是在VS的“项目属性 -> 常规 -> MFC的使用”里选择“在静态库中使用MFC”,再把“运行时库”改成“多线程(/MT)”,这样编译出来的exe不再依赖MFC的DLL和运行时库DLL,体积会从不到1MB膨胀到几十MB,但拿到任何Windows机器上都能跑。这是课设交作业前最省心的发布方式。

如果你选择动态库方式,就要把工程目录下的DebugRelease文件夹里除了exe之外的DLL全部拷贝到目标文件夹,常见的是mfc120u.dllmsvcr120.dllmsvcp120.dll,还有你用的MySQL的libmysql.dll。注意,libmysql.dll不在系统目录,必须和exe放一起。打包发布时,千万别只拷exe,这是最常被坑的地方。

另外还要注意如果你用了MySQL,目标机器上必须装了MySQL客户端或者至少能通过网络访问到MySQL服务器。如果你的数据库是本地服务器且设置了服务自动启动,那演示时记得把MySQL服务提前打开,不然程序启动时数据库连接失败,界面一片空白。

5.2 典型的运行报错和排查方案

在实际开发和答辩演示中,有几个报错几乎是必现的。我把它们总结成一张速查表,每个做MFC+MySQL的人都该收藏。

现象根因解决方案
编译时报“无法打开包含文件mysql.h”没有正确配置include目录项目属性 -> VC++目录 -> 包含目录,加上MySQL的include路径
链接时报“无法解析的外部符号mysql_init”没有链接libmysql.lib项目属性 -> 链接器 -> 输入 -> 附加依赖项,加上libmysql.lib
运行时报“0xc000007b”系统缺少运行库或架构不匹配检查exe是x86还是x64,libmysql.dll也要匹配同架构
界面中文全部乱码字符集编码不匹配连接后执行SET NAMES UTF8MB4,程序内用CW2A/CA2W转换
数据库连接超时MySQL服务未启动或端口不对检查mysql服务状态,确认端口3306可访问

注意一个非常隐蔽的坑:如果你的系统是64位的,但MFC工程是x86平台(32位),那么链接libmysql.lib时也必须使用32位的lib文件,也就是MySQL安装目录下的lib\vs12lib\vs14文件夹中的32位版本。用64位的lib去链接32位程序,链接阶段会报大量错误,这个错误信息很迷惑人,容易让人以为是代码问题。

注意:发布时如果用了MySQL C API,目标机器还必须能访问到libmysql.dll。就算所有MFC运行库都齐了,缺少这个动态库,程序照样弹窗报“无法启动因为计算机中丢失libmysql.dll”。

5.3 界面卡死的排查:别让数据库操作阻塞UI

MFC的程序是单线程的,消息循环跑在主线程上。如果你的mysql_query查询耗时太长(比如站表数据量极大或者网络连接MySQL服务器延迟高),界面就会卡死,表现为鼠标能移动但点不动任何控件,任务管理器里显示“未响应”。

解决方式是开一个工作线程做数据库查询,查询完成后通过PostMessage发送自定义消息给主线程,然后在主线程的消息处理函数里把查询结果更新到界面。这个模式在MFC里叫“工作者线程+自定义消息”,很多初学者听都没听说过,但在实际项目中是必须掌握的。代码核心就两句话:AfxBeginThread(QueryThreadProc, this)开启线程,PostMessage(WM_QUERY_DONE)通知界面更新。

课设阶段数据量不大,主线程查询延时几乎为零,但如果连的是远程MySQL数据库(比如你在实验室连老师的服务器),网络延时就不可忽视了。我当时帮学弟测试时就发现,连本地数据库秒出,连远程数据库要卡个两三秒,这种体验太差了。

6. 踩坑记录与答辩心得

最后说几个我在实际开发中遇到的、网上教程不会写的细节。

第一个是对话框背景色和控件背景色不一致的心得。MFC对话框的默认背景色是COLOR_BTNFACE浅灰色,但如果你用OnCtlColor改了主对话框的背景色为白色,那么所有按钮和编辑框的默认背景还是会保持灰色,看起来很突兀。处理方式是在OnCtlColor里判断控件类型,对CTLCOLOR_BTNCTLCOLOR_STATIC单独设置背景为白色,这样整体风格才统一。

第二个是CSplitterWnd切分窗口的用法。如果想做一个类似资源管理器的界面,左边是树形控件、右边是信息显示,可以用CSplitterWnd把主窗口分成左右两栏。但CSplitterWnd和对话框不能直接混合使用,它基于CFrameWnd。所以如果你用的是对话框类CDialogEx,做不了切分窗口,只能用CTreeCtrl固定放在左边然后调整右边控件的位置。这个限制很多初学都没意识到,花了一晚上怎么都拖不进去切分条,查资料才发现是框架类型不对。

第三个是给树控件加右键菜单。站点查询系统里加一个右键菜单,右键点击某个站点可以弹出“查看相邻站”“设为起点”等选项,这个交互细节很加分。实现原理是响应NM_RCLICK通知,获取鼠标位置并调用CTreeCtrl::HitTest判断点中的是哪个项,然后CMenu加载菜单资源并TrackPopupMenu显示。整个过程不难,但需要细心处理坐标转换,因为GetCursorPos获取的是屏幕坐标,树控件里操作需要转换成客户区坐标,否则菜单弹出的位置是乱的。

写到这里,这个项目的核心内容基本覆盖完了。做MFC地铁查询系统这个课设,最大的收获不是数据库有多熟练、算法有多高级,而是把所有零散的知识点串成了一个完整的桌面应用:控件怎么布局、数据库怎么设计、算法怎么和界面交互、打包发布怎么处理依赖。这个过程走一遍,你就不再看不起MFC这种“老古董”了——它虽然老,但该有的框架思想一个都不缺,消息驱动、事件响应、数据与界面分离,这些概念放到今天任何一个GUI框架里都是通用的。

最后再分享一个答辩时的经验:演示时优先展示换乘查询功能,输入一个跨越三四条线的起点终点,让程序转一圈算出来,这时候UI的响应速度、结果的正确性、换乘信息的可读性,就是整个项目最好的门面。然后把数据库连接字符串那里稍微改一改,现场把MySQL服务断掉再查询,弹出友好的“数据库连接失败”提示而不是崩溃,就这一个细节就能让老师觉得你考虑得很周全。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 3:32:53

ECC内存错误排查与MBIST自检:从原理到实战

引言&#xff0c;先聊点没写在官方手册里的经验 大概半年前&#xff0c;我负责的一台存储节点突然在监控面板里亮起了黄灯&#xff0c;登陆服务器用 dmesg 一翻&#xff0c;满屏都是 EDAC MC0: UE row 15, channel 0, label "CPU_SrcID#0_MC#0_Chan#0_DIMM#1" 这…

作者头像 李华
网站建设 2026/9/8 3:29:40

AI舞蹈生成技术解析:从音乐特征提取到扩散模型实践

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

作者头像 李华
网站建设 2026/9/8 3:29:19

CG提取工具全解析:从解包原理到无损导出与合法边界

简介&#xff1a;CG提取工具包面向游戏汉化、模型复用与逆向分析人群&#xff0c;可帮助用户从游戏中导出立绘、背景、模型、动画等资源&#xff0c;省去手动抓包和格式转换的繁琐流程。压缩包共含520个文件&#xff0c;大小5.56MB&#xff0c;其中txt文档325个&#xff0c;cui…

作者头像 李华
网站建设 2026/9/8 3:29:12

有限集合上的数学结构地图:从概念到Python枚举实战

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

作者头像 李华
网站建设 2026/9/8 3:29:07

自动化测试框架从0到1落地指南:选型、分层与CI集成

最近几年接到不少朋友和团队同行问同一个问题&#xff1a;自动化测试框架到底怎么落地&#xff1f;很多人不是不会写脚本&#xff0c;不是没用过Selenium或者Requests&#xff0c;而是卡在“从0到1怎么搭”“搭起来之后怎么让团队真用起来”这两步上。正好借这篇博客&#xff0…

作者头像 李华
网站建设 2026/9/8 3:28:45

从CANoe到HiL测试:硬件在环系统与自动化测试进阶路线

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

作者头像 李华