CATIA V5二次开发:Selection.Search实现批量选择与自动化批处理 1. 为什么批量选择非要用 Search一次管路批量选择的现场教训1.1 手动点选的三个致命痛点前阵子接了个液压管路布置模型的梳理工作模型不大但里面密密麻麻排了三百多个管夹、接头、过渡块。我需要把同系列的管夹全部高亮出来核对型号和安装位置。刚开始我老老实实按住 Ctrl 在特征树里点点了不到五十个就觉得不对劲一是树节点折叠状态不一样很多同类零件藏在不同的子装配里找不全二是眼睛花了之后容易点错高亮到旁边的支架或者螺栓整个选择集就乱了。这种场景对干过大型装配体的人来说太熟悉了越大的模型手动批量选择的效率越低。就算你把特征树全部展开几千个节点密密麻麻摆在一起靠滚动条和肉眼去筛漏选是大概率事件。而且 CATIA 的选择还有一个小脾气你从树上一个一个点的时候如果中间不小心点到了 3D 图形区的空白处之前的选择经常会被清掉前功尽弃。第二个痛点是手动选择无法被“复用”。你做完了这一轮检查下次换一个类似产品还要重新来一遍你辛苦点选出来的那一堆元素也没法沉淀成工具给同事用。像管夹这种数量大、分布散、命名又带明显规律的对象比如 CLAMP_25、CLAMP_32完全可以用一段代码按名称特征批量捞出比人肉点选可靠得多。第三个痛点是“选择本身真不是目的”。选完之后往往要接着做操作比如统一隐藏、导出清单、批量改名、检查遗漏。如果是手动点选出来的选择集后续再写代码去处理时对象数据不完整、类型混杂处理起来很麻烦。而用 Search 批选出来的结果可以统一遍历、统一过滤后续脚本写起来顺手很多。1.2 理解的入口CATIA 自动化里的 Selection 与 Search 是什么CATIA V5 的自动化接口里几乎所有文档都带一个Selection对象。你平时在图形区或特征树上高亮出来的内容就是这个对象里的元素。它既是一个容器也是很多批处理操作的起点。Selection对象常用的能力有这些Add加一个对象进选择集Remove移除一个Clear清空全部Count看当前选了几个Item(i)按序号取里面的元素。这些都是常规操作但真正让选择集在大模型里发挥威力的是它的Search方法。Selection.Search从名字上就能看出来它干的是“搜索式选择”。你给一段查询条件字符串它按条件在文档里找到所有匹配的元素放回当前选择集。搜索逻辑类似你在命令框里用了“编辑/搜索”那个望远镜图标但好处是整个过程完全脚本化可以反复执行、精确控制、嵌入更大的自动化流程。对于做二次开发的人来说Search 最大的价值不是“少点几次鼠标”而是它把选择标准从人的眼睛变成了可维护的规则。只要命名规范统一、类型明确一段几十行的宏就能替人完成过去需要十分钟甚至半小时才能做完的筛选工作。1.3 一段最短代码先跑通我在讲语法和坑之前先给一段能用 5 分钟验证的最小宏。打开 CATIA随便新建或打开一个零件按AltF8或者从菜单工具 → 宏 → 宏进入宏编辑窗口新建一个模块把下面代码放进去运行Sub SelectByNameKeyword() Dim doc As Document Set doc CATIA.ActiveDocument If doc Is Nothing Then MsgBox 请先打开一个文档 Exit Sub End If Dim sel As Selection Set sel doc.Selection sel.Clear 关键语句搜索所有名称里含有 Part 的元素 sel.Search Name:*Part* MsgBox 搜到 sel.Count 个对象 End Sub第一次跑这个宏哪怕搜出来 0 个也没关系重点是你先把接口跑通了。如果弹窗显示的数量大于 0恭喜你后续所有花活都建立在这条Search语句之上。这时你可以打开特征树看凡是名称里带Part的元素都被自动高亮了说明搜索确实已经生效。很多朋友第一次都会在Selection前面卡住因为 CATIA 的自动化接口文档不好翻到处是英文。你只要记住一个核心逻辑CATIA.ActiveDocument.Selection就是当前高亮选择集Selection.Search就是往这个集中灌元素的方法后面一切都好说。2. Search 条件串到底怎么拼Name、Type 与它会坑人的通配符2.1 基本查询条件和作用范围Selection.Search后面跟的是字符串字符串格式通常是“条件前缀:取值”。我在常见版本里验证最多的有两类Name和Type。表格整理如下条件前缀常用取值说明Name任意文本匹配元素名称支持通配符最实用TypePart/Product/Feature/Edge/Face/Sketch等按对象类型过滤PartNumber产品零件编号在产品文档里按 PartNumber 过滤装配管理常用Family视版本而定有些版本支持按特征族分类不稳定时别全指望它注意Name:*Part*这种写法的意思是“名称里任意位置含有 Part”。如果写Name:Part*就只匹配以 Part 开头的对象如果写Name:*.1匹配的是名称最后以.1结尾的对象。Type条件也很有用比如我想只选装配体里的所有零件实例而不是把曲面、点、线框全选进来就可以用Type:Part。在零件文档里想快速选出所有曲面元素可以试Type:Surface想选几何图形集可能要用Type:GeoSet之类的关键字。关键问题是这些类型关键字在不同版本里不完全一样在 V5 R21 上能用的条件在 V5-6R2019 上不一定能返回同样结果所以我一直建议先用极简字符串试通再往复杂里加不要一下子上来就写一个十层嵌套的组合条件。2.2 文本表达式里的分号、引号、星号和点号Search 字符串乍一看简单真正写起来坑不少。第一个坑是星号的位置。Name:*圆心*和Name:圆心*匹配的范围完全不同写之前要搞清楚名称规律。如果对象的命名规则是“FLANGE_25.1”那Name:FLANGE*能匹配到Name:*25.1也能匹配到但Name:*FLANGE*25*这种写法在不同版本里表现不一定统一我一般把它拆成两步先 Search 一把粗结果再用 VBA 二次过滤。第二个坑是名称里的点号和括号。CATIA 树的默认名称通常长得像Part1.1、Pad.1点在里面是普通字符但某些特殊的搜索解析器会把它当作特殊符号处理。匹配这种名称时最好用双引号把精确名称包起来比如sel.Search Name:Part1.1这段代码里外两层引号是 VBA 字符串转义最终传给 Search 的字符串其实是Name:Part1.1告诉它匹配精确名称Part1.1。如果不加引号你可能发现Name:Part1.1也能匹配但一旦名称里有空格、括号、加号这种特殊符号不加引号就容易出幺蛾子。第三个坑是标点符号全角和半角。很多代码不是手敲的是从网页、PDF、聊天记录里复制出来的里面的引号、分号、括号可能是全角中文格式。CATIA 的 Search 解析器不认全角标点看起来一样的字符串实际跑起来一条也搜不到。遇到这种情况先检查代码编辑器里的符号是不是标准半角。第四个坑是大小写。Search 条件整体上对大小写不敏感但元素的真实名称有大小写之分。我的习惯是所有关键字都用全小写比如name:*flange*即便版本解析器抽风小写出错的概率也低一些。2.3 条件组合的常见写法与我的建议很多教程里会告诉你Search支持非常复杂的组合表达式比如Name:*A* Type:Part。实际项目里我不太建议一上来就依赖这种复杂组合因为 CATIA 各个版本的 Search 语法文档不够透明你写了一个自以为没问题的组合它可能直接返回 0而且不报任何错误排查起来特别费劲。我的习惯做法是先宽后严Search 只做粗筛VBA 再做精筛。比如要选“所有名称带 FLANGE 的 Product”我这么写Dim sel As Selection Set sel CATIA.ActiveDocument.Selection sel.Clear 第一步按名称关键字粗筛 sel.Search Name:*FLANGE* 第二步逐个遍历过滤类型 Dim i As Integer For i sel.Count To 1 Step -1 Dim currentObj As Object Set currentObj sel.Item(i).Value If TypeName(currentObj) Product Then sel.Remove i End If Next这个思路最大好处是每一步都能看到中间结果哪里不对马上能定位。sel.Remove i可以把不符合条件的对象从当前选择集里踢掉剩下的就是你要的最终目标。如果你真的学会了这种“Search 粗筛 代码精筛”的套路后面不管遇到多挑剔的筛选规则都能用几行代码拼出来。3. 可复用的批选宏从单文件到整装配体的完整代码3.1 第一步安全获取活动文档和 Selection写宏不能一开始就假设用户肯定开着某个特定类型文档万一当前窗口是个工程图、装配体或者根本没有文档代码一跑就报错。规范的写法是拿到CATIA.ActiveDocument之后先判断它存在然后用TypeName或Doc.Documents.Count看当前文档类型再往下执行。Public Sub BatchSelectElements() On Error Resume Next Dim doc As Document Set doc CATIA.ActiveDocument If Err.Number 0 Then MsgBox 当前没有打开任何文档请先打开 CATPart 或 CATProduct Exit Sub End If On Error GoTo 0 Dim sel As Selection Set sel doc.Selection sel.Clear 这里先不执行搜索先把环境和对象都确认好 MsgBox 已获取当前文档 doc.FullName End Sub这段代码本身没什么技术含量但它把最容易翻车的空引用问题拦住了。后面你再往里加Search或者其他业务逻辑就不用担心用户忘了开文档导致宏直接崩溃。3.2 第二步构造搜索串并执行 Search最常规的批选需求是“让用户输入一个关键字然后把名称里含有关键字的对象全选出来”。用InputBox和Search配合实现非常直接Public Sub SelectByKeyword() Dim doc As Document Set doc CATIA.ActiveDocument If doc Is Nothing Then Exit Sub Dim kw As String kw Trim(InputBox(请输入名称关键字留空则选择全部名称对象, CATIA 批量选择)) If Len(kw) 0 Then kw * Else kw * kw * End If Dim sel As Selection Set sel doc.Selection sel.Clear sel.Search Name: kw MsgBox 选择完成共选中 sel.Count 个对象 End Sub输入FLANGE就会选中名称里包含 FLANGE 的对象输入25就会选中名称里包含 25 的对象非常实用。建议每次执行前都用sel.Clear清一把旧选择集否则上一次高亮结果和新结果混在一起计数会混乱。搜完以后你可以直接看 3D 区被选中的对象会高亮出来。如果数量太多图形区卡也可以先在特征树里看高亮行或者直接看弹窗里的 Count 数心里有数。3.3 第三步遍历 SelectedItems 处理后续业务sel.Item(i)返回的是一个SelectedElement你需要通过.Value拿它背后真正的 CATIA 对象再进一步操作。比如我想把选出来所有对象的名称输出到“立即窗口”方便核对Public Sub PrintSelectedItems() Dim sel As Selection Set sel CATIA.ActiveDocument.Selection Dim i As Integer For i 1 To sel.Count Dim obj As Object Set obj sel.Item(i).Value Debug.Print i : obj.Name Next End SubDebug.Print在 VBA 里输出到立即窗口在 CATIA 的宏编辑器里用CtrlG可以查看。你也可以改成输出成一个文本文件这样在超大模型里做清单核对更直观。这里有一个细节在遍历选择集的同时不要随便sel.Clear或者执行新的Search因为一旦选择集内容变化sel.Item(i).Value获取的对象可能跟着变空。我习惯先把结果复制到数组里更新完数组后再统一处理避免边遍历边修改选择集带来的各种诡异现象。3.4 完整代码清单与三种执行方式把上面三块拼起来一个能实际用的批选宏大概是这个样子Public Sub BatchSelectByKeyword() On Error Resume Next Dim doc As Document Set doc CATIA.ActiveDocument If Err.Number 0 Then MsgBox 请先打开文档 Exit Sub End If On Error GoTo 0 Dim kw As String kw Trim(InputBox(请输入名称关键字留空选全部, 批量选择)) If Len(kw) 0 Then kw * Else kw * kw * Dim sel As Selection Set sel doc.Selection sel.Clear sel.Search Name: kw If sel.Count 0 Then MsgBox 没有匹配到任何对象 Exit Sub End If 遍历并输出名称清单 Dim logPath As String logPath D:\selection_log.txt Open logPath For Output As #1 Dim i As Integer For i 1 To sel.Count Dim obj As Object Set obj sel.Item(i).Value Print #1, i vbTab obj.Name Next Close #1 MsgBox 选中共 sel.Count 个对象清单已输出到 logPath End Sub执行方式有三种大家按自己习惯选在 CATIA 宏编辑器里直接运行。这是开发阶段最常用的方式调试方便能直接看Debug.Print和报错。把宏挂到工具栏或自定义命令上。通过工具 → 自定义 → 命令 → 宏把宏拖到一个命令按钮上以后点图标就能跑适合自己日常使用或给同事分发。用外部.vbs脚本通过 COM 调用。这种方式不用打开宏编辑器适合自动化集成。示例如下 外部 VBS 脚本双击运行或在命令行中执行 On Error Resume Next Dim CATIA Set CATIA GetObject(, CATIA.Application) If CATIA Is Nothing Then MsgBox CATIA 未启动 WScript.Quit End If Dim doc Set doc CATIA.ActiveDocument If doc Is Nothing Then MsgBox 没有活动文档 WScript.Quit End If Dim sel Set sel doc.Selection sel.Clear sel.Search Name:*FLANGE* WScript.Echo 选中的数量 sel.Count外部 VBS 的好处是后续可以和 ERP、PDM 或其他软件做集成坏处是出错时排查不如 VBA 方便。我通常先用 VBA 把逻辑调通稳定后再转成.vbs分发给现场使用。4. 运行现场的高频报错与三个你看不出来的坑4.1 搜索后 Count0元素明明就在树上这是最多人遇到的怪问题代码明明执行了也没报错但sel.Count就是 0。我排查下来的主要原因有三个。第一个原因是当前的活动文档和你想搜的文档不是同一个。用户可能同时开着 CATPart 和 CATIA 自带的一些窗口当前焦点落在工程图上CATIA.ActiveDocument拿到的是工程图里面当然搜不到零件特征。这时可以改成按固定名称取文档或者让宏先弹窗提示当前文档名。第二个原因是工作对象Working Object的范围限制。有时候你在一个 Product 文档里但当前工作对象卡在某个子 Part 上Search 默认只搜当前工作对象范围内的内容结果自然不全。你可以先手动双击某个顶层产品的树节点把工作对象切回顶层再重新跑宏。第三个原因是搜索关键字和实际名称对不上。CATIA 树上的显示名不一定等于自动化对象里的真实Name。比如显示名可能是“凸台.1”但底层特征名也许是Pad.1或者显示名是中文实际存储名是英文。这种情况你把对象真实名称打出来看一眼立刻能找到答案。4.2 “类型不匹配”或运行为空对象的真相用sel.Item(i).Value拿对象后马上.Name在部分元素上可能报“对象不支持该属性或方法”。原因是选择集里的元素不全是同一类对象有特征、有产品、有点线面它们暴露并不完全一致。我处理这类问题的原则是先看 TypeName再决定调用哪些接口For i 1 To sel.Count Dim obj As Object Set obj sel.Item(i).Value Debug.Print TypeName(obj) If TypeName(obj) Product Then 在这里执行 Product 专属操作 ElseIf TypeName(obj) Part Then 在这里执行 Part 专属操作 End If Next这么做虽然代码长一点但非常稳。不要指望一个通用变量能兼容所有对象模型实际的项目对象类型往往比你预想的多得多。4.3 大装配体里 Search 卡死先缩小范围再动手有人执行sel.Search Name:*想让 CATIA 选半天结果图形区转圈转了十几分钟。这个问题本质上不是 Search 方法低效而是你要选的量实在太大了。把所有元素全部灌进选择集还要高亮刷新再大的机器也得卡。我的建议是永远不要在大模型里做无差别全选。如果你只是想把某个类型或者某段前缀的元素捞出来一定要把条件写精确。能用Type:Product就不用Name:*能用PartNumber:*FLG*就不用Name:*. 如果你想搜的对象分布很广也可以分多次小范围 Search每搜完一次立刻把结果存进数组或临时集合而不是指望一次把所有东西都塞进当前选择集。另外如果模型实在太大可以在执行宏之前先在 CATIA 选项里把“图形性能”和“深度缓存”调整一下或者把特征树折叠起来减少刷新开销。这个属于操作层面的优化虽然不解决代码本质问题但能明显改善运行体验。4.4 把选择结果变成真正的“活对象”还有一个很容易误用的地方是很多新手以为sel.Item(i)就是实际的特征或产品可以直接调用Part.Pad1之类的接口。其实SelectedElement只是选择集项.Value才是被选中的对象引用.Reference在某些场景下才是你需要的“引用对象”。当你需要对选中的对象做后续操作时正确姿势是Dim product As Product Set product sel.Item(1).Value但如果你只是想把这个对象“锁”进一个 Reference 集合后续做干涉检查或者测量可能要用sel.Item(1).Reference。说白了Value是给你操作真实实体用的Reference是给你在装配约束、测量、干涉分析里引用用的。用混了就会出现“明明选到了却没效果”的怪现象。5. 从“选中”到“干活的宏”三个我能直接用的扩展方向5.1 隐藏/显示和可见层级的批量控制批量选择最常见的用途就是批量隐藏或显示。把一批同类管夹从图形区里暂隐或者把一类螺栓全亮出来代码写起来非常短Public Sub HideSelectedProducts() Dim sel As Selection Set sel CATIA.ActiveDocument.Selection sel.Clear sel.Search Type:Product; Name:*CLAMP* Dim i As Integer For i 1 To sel.Count Dim p As Product Set p sel.Item(i).Value 不同版本接口有差异有的用 VisProperty.Show False p.VisProperty.Show False Next End Sub如果你在用 V5-6R2020 或更高的版本VisProperty.Show这个属性可能还是有效的如果版本太新或者太老可以用对象浏览器搜一下VisProperty成员确认具体写法。批隐藏的风险是容易把不该藏的东西也藏了所以我不建议一上来就全模型隐藏宁可先精确 Search 出目标确认数量后再执行隐藏。5.2 批量改名、批量加属性避免在树上一个个点把 Search 批量选择与改名、属性维护结合起来效率提升非常明显。比如我需要给所有CLAMP_*产品加一个“批次号”参数手动在特征树上一个个加会疯掉代码则不需要Public Sub AddBatchAttribute() Dim sel As Selection Set sel CATIA.ActiveDocument.Selection sel.Clear sel.Search Name:*CLAMP* Dim i As Integer For i 1 To sel.Count Dim p As Product Set p sel.Item(i).Value 判断参数是否存在存在则覆盖不存在则新建 On Error Resume Next Dim prm As Parameter Set prm p.UserRefProperties.Item(BatchNo) If Err.Number 0 Then Err.Clear Set prm p.UserRefProperties.CreateString(BatchNo, ) End If On Error GoTo 0 If Not prm Is Nothing Then prm.Value BATCH-2024-001 End If Next End Sub这里UserRefProperties是产品上的用户引用参数集合。用这个方法批量维护属性比在树上一个个右键输入靠谱得多。不过要提醒一句给对象批量赋名前一定要先搞清楚命名规范否则改错一串产品零件号恢复起来比手动点还痛苦。5.3 做一个人人可用的“搜索工具箱”当 Search 宏在公司内部逐渐流传后我建议把它做成一个“搜索工具箱”而不是一个孤立宏。工具箱可以做成一个带窗体的 VBA 工具窗体上有关键字输入框、类型下拉框、结果显示列表框点“搜索”后把匹配到的名称列表展示出来再点“导出”或“隐藏”执行后续命令。限于篇幅我不把完整的 UserForm 代码贴出来了但可以给一个思路。窗体代码里调用 Search 的方式和普通宏完全没有区别只是把InputBox换成文本框把MsgBox换成列表框展示。这事的难点不在 Search而在你是否愿意花时间把 UI 做得顺手。做成工具箱还有一个额外好处可以把你平时积累的命名规则、类型关键字、常用筛选条件预设成按钮让不懂 VBA 的同事也能直接用。这个价值远大于你身边人拿到的单个宏脚本。5.4 一个容易被忽略的经验宏里的错误处理与回滚最后说一个经验也是踩过不少次坑才总结出来的批处理宏一定要做错误处理和操作日志。你面对的不是十来个对象是几百上千个对象中间只要有一个对象接口异常宏就可能中断更麻烦的是前面已经改过的对象不会自动回滚。我的标准做法是在每个可能出错的操作后面都检查Err.Number同时把成功修改的对象名称写进日志文件For i 1 To sel.Count On Error Resume Next 业务操作 Err.Clear If Err.Number 0 Then Print #1, OK vbTab obj.Name Else Print #1, FAIL vbTab obj.Name vbTab Err.Description End If On Error GoTo 0 Next有了这份日志出问题后你能精确知道哪些对象成功、哪些对象失败然后针对性处理。没有日志的批处理宏就像没有导航的夜车开着开着就不知道自己在哪了。用不了多少代码量但关键时刻能救你一次。我自己现在写任何涉及批量修改的宏都默认在开头把原对象的名称、规格、原参数值输出到日志操作完再输出新值。这样做另外一个好处是同事问起来“这个宏改了哪些东西”时我能直接给他一份清单而不是让他自己去翻模型。你在做 Search 批选时如果也能顺手把这套日志习惯加上省下的时间会比你想象的多得多。