资讯详情

资讯详情

NX二次开发过滤器设置指南:Selection与BlockStyler方案详解

做NX二次开发这几年我遇到过不少同事提同一个需求做工艺辅助工具时界面里要选几个面、选几个体但经常一选就选了一大堆或者选到不该选的对象。早期我自己也犯过这个错误写了个选孔的工具用户点一下就蹦出来几十个同名对象程序直接卡死。后来才明白问题不在选择逻辑而在选择入口——过滤器没设对。过滤器这个东西放在NX二次开发里本质上就是你给用户的选择行为套上一层“允许/不允许”的规则。它决定了一件事用户鼠标点下去的时候哪些对象能被选中、哪些会被自动忽略。很多新手一开始只关注几何运算、特征遍历这些功能等到交互环节才发现没有过滤器整个工具就像没装门禁的停车场什么车都能进来。目前主流的过滤器设置方案主要有两种一种是在NXOpen的Selection管理器上直接挂过滤条件预过滤一种是在UI界面控件上做类型限制再叠加代码里的二次校验后置过滤。这两套方案各有各的适用场景这篇就来把这个话题拆开聊透。1. 过滤器方案选型先搞清楚你要拦哪一层1.1 从一次误选事故说起讲一个我实际遇到过的案例。有段时间我给一个注塑模项目写装配自动化的辅助工具功能是让用户选中产品上的某个关键面然后程序自动把这一圈的滑块面、斜顶面全部标出来。这个需求听起来简单但实际部署到车间之后工人反馈说“根本没法用”。我跑过去一看问题出得非常直接——用户在选择面的过程中鼠标稍微晃一下选中的就是装配体里的另一个零件面或者干脆把整个片体、基准面、草图曲面的对象都选进来了程序一拿到这个错误的Tag后面的几何遍历就全乱了。这个教训让我意识到在NX这种大型CAD平台里做交互选择过滤器不是“锦上添花”而是“保命”的一环。尤其是装配体环境下模型树里动辄几千个对象用户不可能靠肉眼一个个分辨哪个是实体面、哪个是片体面、哪个是基准面。过滤器的本质作用就是在用户点击的瞬间帮系统排出掉那些不符合业务规则的对象让用户“想选错都难”。另外有些朋友搜索“UG过滤器怎么调出”其实问的是NX界面自带的那个选择过滤器工具条。在NX里图形窗口左上角就有一排快速过滤器图标可以控制当前会话允许拾取的对象类型。但那只是交互层面的临时设置跟我们二次开发代码里设置的过滤器是两回事。开发时你得通过SelectionManager来编程控制界面上那排开关管不到你的代码逻辑。这个区别很重要很多初学者像我当初一样没搞清楚结果在界面上调了一通过滤器代码里还是一样漏选。1.2 两种主流方案的定位差异那么“两种过滤器方案”到底指哪两种在NX二次开发的实际语境里我理解的是这样一组关系方案ANXOpen Selection类过滤器预过滤。在代码里直接向SelectionManager注册一套过滤条件类型、子类型、掩码状态用户还没有点进图形窗口NX就已经把允许选中的对象集合限定好了。这个方案适合批量选择、无界面的脚本型工具或者以命令方式弹出的选择循环。方案BBlockStyler控件 二次校验后置过滤。用户在UI对话框里通过SelectObject控件做选择控件本身可以配置类型范围但真正精细化的过滤——比如按图层、按属性、按名称规律——需要控件选中之后在回调里再一次校验和拦截。这个方案适合有正式用户界面的工具能跟整个BlockStyler的生命周期结合在一起。这两套方案不是互相替代的关系而是“预过滤负责粗筛后置过滤负责精筛”的分工关系。实际做项目时我经常两个一起用——Selection那层拦类型回调里再拦业务规则。1.3 选型判断什么场景该用哪一种选型其实不难判断。没有正式UI的比如用户要用命令行或者快捷键触发、然后直接进入连续选择状态基本走方案A有UI对话框的、需要用户填多个参数的基本走方案B。具体还可以参考这几个问题用户选择的对象类型是否单一清晰比如只要面那就是类型过滤为主。除了类型有没有额外的业务条件比如“选出的面必须属于当前激活工作部件”“必须在指定图层”——这种就必须上二次校验。选择要不要配合预览、高亮和说明文字比如告诉你“当前已选择3个对象还需选择1个”这种界面交互体验要走BlockStyler。代码要不要兼容旧版本NX或者沿用老的UF习惯如果团队手里的历史代码大量使用UF_UI相关接口那方案A的思路就能用UF接口实现对等效果。这个判断方法无脑直接用就行。我自己一般是在项目一开始就把这两个问题问清楚免得写到一半发现过滤器的层级搞反了又得回炉重写。2. 方案ANXOpen Selection类型过滤器的完整用法2.1 Selection核心API与过滤原理先花一分钟把NXOpen里Selection的工作原理说清楚。NXOpen.Selection通常通过ui.SelectionManager拿到的那个对象是NX给开发者提供的选择管理器它负责维护“当前会话里哪些对象可以被选中”。最常用的API是SetFilter。它有好几种重载核心都能归为两类按单个Criteria过滤ui.SelectionManager.SetFilter(FaceOnly, new Selection.Criteria(Selection.Type.Face, Selection.SubType.Any));按掩码组合过滤Selection.FilterTypes[] types new Selection.FilterTypes[2]; Selection.MaskTriState[] states new Selection.MaskTriState[2]; types[0] Selection.FilterTypes.Face; states[0] Selection.MaskTriState.Only; types[1] Selection.FilterTypes.Body; states[1] Selection.MaskTriState.Blocked; ui.SelectionManager.SetFilter(FaceOnlyWithBodyBlocked, types, states);这两种写法的原理是一样的——都是在NX的选择引擎中设置一个“白名单/黑名单”的组合SelectionManager会在用户每次点击时把命中的对象拿去做类型匹配匹配不上的直接忽略。2.2 实操按面/体/特征类型精确过滤实际项目里最常遇到的需求就两种选面、选体。选面而且是只要实体的面、不要片体也不要基准面。由于Selection.Type.Face其实涵盖了多种几何面形态建议在Criteria上做细分。NXOpen里你可以通过Selection.SubType来指定子类型比如Selection.Criteria criteria new Selection.Criteria(Selection.Type.Face, Selection.SubType.Any); ui.SelectionManager.SetFilter(SolidFaceOnly, criteria);这里用SubType.Any是相对宽容的写法如果你明确知道业务只针对平面可以写成更具体的子类型。不过要提醒一句Selection.SubType枚举在各个NX版本里名称有差异写代码前先查一下当前版本的API文档安装目录下找个.chm或docs文件夹关键词“Selection.SubType”一搜就有。选体的时候也一样只要实体、不要片体Selection.Criteria bodyCriteria new Selection.Criteria(Selection.Type.Body, Selection.SubType.SolidBody); ui.SelectionManager.SetFilter(SolidBodyOnly, bodyCriteria);关于选特征比如隐藏的孔特征、倒角特征可以走Selection.Type.Feature配合过滤。注意特征选择和几何对象选择是两条不同的路径比如你选了孔特征拿到的是Feature对象想再往上拿对应的面要通过GetFaces这类API做桥接这是另一个话题了。2.3 掩码组合与精细控制当业务需求不只是“只要面”这么简单而是要“只要A图层上的面、且不要已经被隐藏的面”时就要用掩码组合写法了。一个我常年用的组合例子要求用户选择可见实体面但不允许选择属于某个特定组件的面防止误选配合件。public void SetupFaceFilter() { Selection.FilterTypes[] types new Selection.FilterTypes[3]; Selection.MaskTriState[] states new Selection.MaskTriState[3]; types[0] Selection.FilterTypes.Face; states[0] Selection.MaskTriState.Only; types[1] Selection.FilterTypes.Csys; states[1] Selection.MaskTriState.Blocked; types[2] Selection.FilterTypes.Body; states[2] Selection.MaskTriState.Blocked; ui.SelectionManager.SetFilter(WorkFaceFilter, types, states); }FilterTypes这个枚举覆盖面挺广的从Curve、Edge、Face、Body到Component、Dimension都有。MaskTriState只有三个值Only、Allowed、Blocked。Only表示“选择集里只允许这个类型”Allowed表示“这个类型可以选但不是必须”Blocked表示“这个类型不允许选”。需要特别注意的是Only和Blocked混用时的语义要仔细想清楚。如果用Only设置了面那其他没列出来的类型都默认不可选这时候再Block一个Body其实没什么意义。所以我的习惯是要么全用Allowed Blocked自由组合要么直接用Only把类型锁死再叠加回调做二次判断。组合写法虽然灵活但别把自己绕进去。3. 方案BBlockStyler控件 二次校验的界面化过滤3.1 SelectObject控件的属性配置方案B的主战场是BlockStyler——NX的UI编辑器。在BlockStyler里拖一个SelectObject控件出来右侧属性面板里就能看到跟过滤相关的选项。常见的几个属性SelectMode单选还是多选。对应代码里的EnableSingleObjectOnly。Scope选择范围。可以限定“整个装配”“仅工作部件”“可见对象”“仅当前显示的图层”等。Type / SubType这里可以在属性面板里直接指定允许的对象类型。EnableHighlight / EnableDragSelect是否允许高亮、框选这俩虽然不直接影响过滤但体验上影响很大。举个例子在BlockStyler里配一个“只允许选择面”的控件属性面板上把Type设为FaceSubType设为Any然后Scope选“VisibleObjects”可见对象这基本上就完成了80%的工作。剩下的20%是关于业务规则的二次校验这才是方案B的精髓。3.2 代码层如何叠加自定义过滤条件属性面板能设的只是类型级别的粗过滤。一旦业务逻辑复杂起来比如说“用户选的面不能是装配下的某个非工作部件里的面”属性面板就无能为力了得在对话框的回调事件里写代码。在NXOpen的BlockStyler架构里SelectObject控件有事件回调比如OnSelectCallback和OnFilterCallback。OnFilterCallback会在对象被最终加入选择集之前触发在这里可以返回true/false来控制某对象是否允许被选中。我这里贴一个我常用的过滤器回调模板private bool OnFilterCallback(SelectObject selectObject, NXOpen.TaggedObject taggedObject) { // 只允许工作部件的面 if (taggedObject is NXOpen.Face face) { NXOpen.Body body face.GetBody(); if (body null) return false; // 判断面所在部件是否是当前工作部件 NXOpen.Part ownerPart body.OwningComponent null ? body.Part : body.OwningComponent.OwningPart; return ownerPart workPart; // workPart 在对话框初始化时缓存 } return false; }这里的代码思路很简单控件层面做了类型过滤之后回调里拿到每一个候选对象再拿它所在的Part跟工作部件比对是同一个部件才能放行。如果说得更细一点还可以在这里结合图层、属性、命名规则只要你能拿到对象就能列判断规则。提醒一句不要在OnFilterCallback里做太重的计算比如遍历整个装配、做几何相交这会让界面卡顿用户体验很差。复杂判断尽量提前缓存结果回调里只用缓存做快速判定。3.3 UI方案与代码方案怎么配合很多人以为方案B就是把BlockStyler的类型属性设置好就完事了其实最佳实践是两个层面同时上控件属性做粗筛去掉明显不相关的类型减少回调触发次数。回调里做精筛满足业务规则才算数。打个比方控件属性像是安检口外的大闸门把背包、宠物这些明显不能进场的挡在外面回调就像场内每个闸机口的工作人员还要再看一眼你的工作证和预约状态。两层配合获得的体验是最稳的。我在项目里通常还会加一个状态栏提示实时告诉用户“当前模式仅可选工作部件的实体面”让用户不用猜过滤器到底拦了什么。这个小细节对一线生产工具非常重要——用户选了半天选不上东西如果没有提示他会以为程序坏了而不会想到是过滤器拦了。4. 实战案例装配体环境下选择关键连结面的场景拆解4.1 需求背景有读者一直问NX二次开发里“连结面”怎么选、怎么过滤。我拿一个实际做过的模具项目来拆解场景是在一个包含几十个零件的装配体里要用户选出产品和模仁之间的关键分模面然后程序据此勾出周边关联的侧抽芯面。这个需求的原始表述是“nx二次开发 连结面”——我理解用户就是想实现“在装配体环境下选一组特定的面集合”。整个功能拆开来看技术点其实只有两个如何让用户在装配体里只选到产品零件上的实体面而不是选到其他零件的面。如何把选到的这一组面归拢到同一个逻辑集合里方便后续几何处理。4.2 用方案A实现方案A的代码实现很直接。先设置过滤器然后进入选择循环。核心代码如下public NXOpen.Face[] SelectKeyFaces() { string sessionTag KeyFaceSelector; // 方案A直接用Selection的Criteria做预过滤 Selection.Criteria criteria new Selection.Criteria(Selection.Type.Face, Selection.SubType.Any); ui.SelectionManager.SetFilter(sessionTag, criteria); Selection.Response response Selection.Response.Null; NXOpen.TaggedObject[] pickedObjects null; try { response ui.SelectionManager.SelectObjects( sessionTag, 请选择产品关键面可多选确认后回车, false, out pickedObjects); } finally { // 用完清掉过滤器避免影响后续其他操作 ui.SelectionManager.ClearFilter(sessionTag); } if (response ! Selection.Response.Ok || pickedObjects null) return new NXOpen.Face[0]; return pickedObjects.OfTypeNXOpen.Face().ToArray(); }这段代码有几个关键细节值得留意第一SelectObjects的第一个参数传的就是刚才SetFilter时的过滤器名NX会根据这个名字去匹配当前可用的过滤规则。第二SelectObjects的第三个参数是是否允许单对象直接确认一般传false让用户通过中键/回车完成多选。第三finally里的ClearFilter非常重要。过滤器是挂在SelectionManager这个全局对象上的如果不清掉下一次别的功能在选择的时候还会沿用这个过滤规则典型的“过滤器污染”。方案A适合无界面工具比如用户在命令行输入命令直接进入选择状态。省去了对话框的资源占用选择循环也是最原生、最敏捷的。4.3 用方案B实现同样这个需求如果做成正式UI界面用BlockStyler会更合适。流程是新建一个BlockStyler对话框拖入一个SelectObject控件。属性面板里Type设为FaceScope设为“当前显示的对象”。在代码里给控件挂一个OnFilterCallback把“只选工作部件里的面”的规则写进去。对话框右下角加一个确定按钮点击后把选中的面List传给后续逻辑。布局大概这样public class MyDialog { private Session theSession; private UI theUI; private BlockStyler.Dialog theDialog; private BlockStyler.SelectObject faceSelector; public void Initialize() { faceSelector.FilterSet OnFilterSet; faceSelector.OnFilterCallback OnFilterCallback; } private bool OnFilterCallback(BlockStyler.SelectObject selectObject, TaggedObject taggedObject) { if (taggedObject is Face face) { return face.GetBody()?.OwningComponent null; // 只允许装配体根节点下的面排除子组件内的面可根据业务调整 } return false; } private void OnFilterSet(BlockStyler.SelectObject selectObject) { // 这里可以再次设置控件的Type等属性跟属性面板效果一样 selectObject.SetFilter(new Selection.Criteria(Selection.Type.Face, Selection.SubType.Any)); } }实际运行效果跟方案A最大的不同是所有基础属性、提示信息、选择状态都能融进同一个对话框里用户可以一边看模型高亮一边调整其他参数。对于生产环境里的工艺人员来说这种体验显然是更友好的。4.4 两种方案处理同一需求的效果对比把同一个需求用两种方案各跑一遍之后我的真实感受是方案A的代码量少、思路清晰适合快速验证、临时脚本、无UI工具。缺点是设置复杂规则时全写在SelectionManager上历史过滤器多了以后容易搞乱。方案B的代码量略多但把“类型过滤”和“业务过滤”分到了两个清晰的位置长期维护性更好。尤其是面向车间用户时UI上的提示和属性配置能显著降低误操作概率。我做工程类工具时如果只是自己或者几个工程师内部用会直接方案A。如果是部署给一线生产人员用一般稳妥选方案B把过滤器的状态可视化地呈现出来宁可多写点回调代码也要降低用户出错的可能性。对比项方案ASelection预过滤方案B控件回调二次校验适用场景无UI脚本、批量工具正式对话框、生产环境类型过滤通过Criteria/掩码控件属性 回调业务规则过滤需要另外写判断回调中直接处理用户提示偏少可以做得更丰富维护成本中略高但清晰5. 过滤器避坑指南我踩过的那些坑5.1 过滤器设置了却不生效这个坑几乎每个新手都会踩。最常见的两种原因第一种过滤器名对不上。SetFilter用了“FaceFilter”SelectObjects的时候传成了“faceFilter”大小写差一个字母NX找不到对应规则自然用的是默认选择行为表现为“没设过滤器一样”。第二种过滤器在别的会话里被覆盖了。NXOpen的SelectionManager在同一个会话里是共享的如果你在多个功能模块之间切换前一个模块ClearFilter不及时后一个模块设置的新过滤器会把旧的顶掉。排查方法很简单把所有SetFilter的地方打印日志看执行顺序。另外还有一个很隐蔽的情况当你用了Selection.Criteria预过滤后如果设置的类型写得太宽比如SubType.Any会覆盖掉一些你本来想排除的子类型。这时候需要用掩码组合把要排除的具体子类型Blocked掉而不是只靠一个Criteria搞定。5.2 误点导致选择中断选择循环跑起来之后用户按ESC或者点了空白区域Selection.Response会返回不同状态码。很多人在处理返回值时只判断Ok忽略了对Cancel的处理这样用户一旦取消程序要么抛异常要么把null当正常返回继续往下执行直接空引用。稳妥的处理方式是if (response Selection.Response.Ok pickedObjects ! null) { // 正常处理 } else if (response Selection.Response.Cancel) { // 提示用户已取消 return new Face[0]; } else { // 其他异常响应 return new Face[0]; }另外一点建议是选择过程中给一个明确的提示文案别就写“请选择对象”最好是“请选择分模面不包含定位边完成后单击中键确认”把操作路径和选择范围都写清楚。5.3 多窗口/多会话下的过滤器隔离NX支持多窗口同时打开虽然用的不多但如果你的工具需要支持多窗口就要特别注意SelectionManager是全局的还是跟窗口关联的。我自己的经验是NXOpen里SelectionManager的过滤器基本是全局的多窗口模式下很容易串场。所以做多窗口支持时建议在每次进入选择循环前重新设置一次过滤器选中结束后立刻清除。还有一个常见场景是“选择完成后还要接着选择”——比如先选产品面再选模仁面。这种情况下两个循环最好用两个不同的过滤器名并且每个循环都独立设置、独立清除避免互相影响。5.4 与UF接口混用的注意事项最后聊一下老牌UF接口的问题。有些人写NX二次开发习惯了UF_UI_select_with_class_filter这类C类接口它的优势是逻辑直接、底层控制力强但跟NXOpen混用时容易踩一些隐性的坑比如Tag类型转换、错误码处理、内存释放等。我自己遇到过的比较典型的问题是UF接口里拿到的tag_t对象想用NXOpen的Face对象来处理时要么通过NXOpen.Utilities.NXObjectManager.Get(ufObject)来转换要么在做几何遍历的时候混合使用UF核心函数。这个转换步骤一旦写错轻则类型不匹配重则导致NX进程崩溃。举个例子很多老工程师习惯用UF_MODL_ask_feat_object来拿特征对象tag_t featTag; // 从UF选择接口拿到 NXOpen.NXObject nxObject NXOpen.Utilities.NXObjectManager.Get(featTag); NXOpen.Features.Feature feature nxObject as NXOpen.Features.Feature;这个转换过程看着简单但因为UF接口返回的是底层tagNXObjectManager.Get对有些对象类型会返回null或抛异常必须加防御性判断。更麻烦的是UF接口的错误码处理很啰嗦一个简单的选择函数调用没多久就写了一堆check返回值。给一个忠告团队项目如果一开始定了NXOpen路线就尽量统一用NXOpen来处理过滤器不要UF和NXOpen混着写。除非某个功能必须走UF比如一些老的UF_MODL操作否则混用的维护成本非常高。UF的函数风格一言难尽错误处理要写很多防御性代码而且NX版本的兼容性要自己验证。问题现象可能原因解决方式过滤器不生效过滤器名拼写不一致统一名称打日志选择中断/空引用未处理Cancel响应判断Response多窗口串场未及时清除过滤器每次选择循环前后Set/Clear与UF互转崩溃类型转换错误用NXObjectManager转换过滤器这个东西表面上只是交互选择的一层配置但实际做深了会发现它直接影响工具的稳定性、误操作率以及用户对整个工具的信心。我在实际项目里的体会是设计过滤器时别一上来就写代码先把业务规则梳理清楚比如“允许哪些类型、排除哪些组件、还要不要看图层和属性”这些规则列清楚了选方案A还是方案B就是明摆着的事。最后再分享一个小技巧过滤器清除之后可以顺手在日志里打印一条“过滤器已重置”不要小看这一行日志。有一次现场部署用户反馈“上次选了面这次再打开工具选不上了”排查到最后就是因为过滤器没有清干净。日志一加这种问题三秒钟就能定位。NX二次开发的交互选择是个老生常谈的话题但越是基础的东西越值得认真对待。希望这篇经验能帮你少踩几个坑。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →