本文还有配套的精品资源,点击获取
简介:这套SolidWorks二次开发资料以实际功能落地为导向,覆盖开发环境配置、常用API类结构与继承关系理解、文档新建/打开/保存等基础操作。重点讲解特征管理器遍历、特征树节点操作,以及拉伸、倒角、倒圆角等核心建模命令的程序化调用方法;提供面、边、顶点等几何元素的获取路径与关联逻辑。装配体部分支持组件遍历、属性读取及BOM表格一键导出为Excel格式。工程图模块聚焦自动化编辑能力,包括视图中尺寸显示控制、前缀后缀批量修改、尺寸公差与形位公差的参数化设置、表面粗糙度符号插入、基准目标标注、技术要求注释等内容的脚本化处理。所有内容按功能模块分章组织,如第七章详解建模特征编程,第十章集中说明工程图注释与公差控制策略,第十二章梳理装配体组件操作与BOM生成流程,每章对应可直接参考的Word文档,编号清晰、接口调用示例明确,便于开发者快速定位并复用代码逻辑。
1. 这不是API文档翻译,而是一份能让你当天写完第一个自动出图脚本的实战手记
我第一次在客户现场被要求“把这50张工程图的公差全部从±0.1改成H7/g6,表面粗糙度统一加Ra1.6符号,基准A、B、C位置不能动但要批量更新字体大小”时,手里的SolidWorks 2020刚打开第3张图,鼠标已经点得发酸。客户工程师坐在旁边看表,我额头冒汗——不是因为热,是因为知道靠手动改完至少得两天,而交付节点是明天下午三点。
那会儿我翻遍了SolidWorks官方API Help,满屏都是IModelDoc2::GetActiveView()、IDrawingDoc::CreateDrawViewFromModelView3()这类接口声明,参数列表长得像电话号码簿,返回值说明里写着“成功返回S_OK”,失败呢?没说。更没人告诉你:为什么调用ISketchManager::CreateCircle()后草图没显示?为什么IAnnotation::SetText()改了尺寸前缀,但工程图里还是空白?为什么BOM导出到Excel时,自定义属性“设计者”列全变成#N/A?
这套资料,就是我在之后三年里,踩着27个真实产线项目、重装过11次SolidWorks开发环境、报废掉4块机械硬盘(全是调试崩溃日志塞满的)后,把所有能抄、能改、能直接粘贴进VS项目的代码段,连同背后“为什么必须这么写”的血泪笔记,一条条抠出来、验证过、压平成可复用模块的成果。它不讲COM组件注册原理,不推导IDispatch接口绑定机制,也不教你如何用C++写一个完整的Add-in外壳——它只回答一个问题:“我现在要让SolidWorks自动做这件事,下一步该敲哪几行代码?”
核心关键词你已经看到了:SolidWorks API是它的语言,特征编程是它的肌肉,BOM导出是它最常被催的交付物,工程图公差是它最棘手的战场,而整套内容的载体,是一份真正按开发者工作流组织的二次开发文档。它适合谁?适合刚拿到公司SolidWorks正版授权、被主管拍着肩膀说“小张,咱们图纸标准化得自动化,你来搞”的应届生;也适合做了十年工艺却第一次听说IConfiguration接口的老工程师;更适合那些已经能写VBA宏、但卡在“怎么让宏识别装配体里某个螺钉的材质属性”上的进阶用户。它不假设你懂.NET反射,但默认你知道右键特征树能“编辑特征”;它不要求你背下所有GUID,但会告诉你swDocumentTypes_e.swDocDRAWING这个枚举值在哪查、为什么必须用它而不是硬编码数字3。
我试过把这份资料给三个不同背景的人:一个机械专业大四学生,三天后交出了自动标注齿轮齿顶圆公差的VB.NET插件;一个PLM系统实施顾问,用第十章的公差批量修改逻辑,两周内把客户旧图纸库的2000+张图完成了ISO 2768-mK标准迁移;还有一个外资车企的CAE工程师,直接拿第七章的拉伸特征参数化模板,重构了他们碰撞仿真前处理的几何建模流程。他们没一个人是从头学COM互操作开始的——他们只是打开Word文档,找到对应功能的章节编号,复制代码,改两行变量名,F5运行,然后看着SolidWorks自己动了起来。
这就是它和市面上90%所谓“SolidWorks二次开发教程”的本质区别:它不教你怎么成为API专家,它只确保你今天下午三点前,能把客户那50张图的公差改完。
2. 内容整体设计与思路拆解:为什么放弃“从零搭建Add-in”老路,选择“功能即模块”的渐进式架构
很多初学者一上来就死在第一步:Visual Studio新建项目,选“SolidWorks Add-in”,然后对着向导生成的几百行模板代码发懵。SwAddin类里一堆ConnectToSW、DisconnectFromSW虚方法,ISwAddin接口继承链绕得人头晕,更别说ICommandGroup菜单注册那一套COM注册表操作。结果花三天配环境,还没碰到底层建模逻辑。这套资料彻底跳过了这个陷阱,它的底层架构设计,源于我在汽车零部件厂现场的真实妥协。
2.1 “功能即模块”:拒绝大而全,拥抱小而准
整套资料没有“第一章:环境配置”,而是直接从第七章:建模特征操作切入。为什么?因为在产线实际需求中,“我要自动创建一个带拔模角的拉伸凸台”永远比“我要注册一个全局Add-in”来得紧急。所以所有代码示例都以独立、可执行的最小单元存在:
CreateExtrudeBossFeature.vb:一个完整的VB.NET控制台程序,双击即可运行,在当前打开的零件中创建指定尺寸、深度、拔模角度的拉伸特征;BatchModifyTolerance.py:一个Python脚本(通过pywin32调用COM),拖拽任意工程图文件到它图标上,自动完成公差格式替换;ExportBOMToExcel.cs:一段C#代码片段,复制进任何已存在的VS项目,传入IAssemblyDoc对象,立刻生成带层级缩进、自定义属性、材料列的Excel BOM。
这种设计不是偷懒,而是基于对SolidWorks API本质的理解:它不是一个需要长期驻留内存的后台服务,而是一个按需触发的命令执行引擎。你不需要让程序一直挂着监听事件,绝大多数自动化任务,本质就是“打开文档→执行操作→保存关闭”。所以资料里所有模块都遵循“三段式”结构:初始化连接(SldWorks.Application获取)、核心操作(调用具体接口)、资源释放(显式调用Marshal.ReleaseComObject)。这样做的好处是:新手可以单点突破,老手可以无缝集成到现有系统,而且每个模块的调试成本极低——出错了,只看这几十行代码就行,不用在上千行Add-in框架里扒日志。
2.2 Word文档即IDE:为什么坚持用章节编号而非代码仓库管理
你看到资源包里有.gitignore、requirements.txt,甚至还有个test_app.vb,但核心内容却是Word文档。这不是倒退,而是深思熟虑的工程决策。在模具厂调试时,我亲眼见过工程师在车间电脑上,一边看着Word文档里的第七章代码,一边在SolidWorks里点开特征树,对照着IFeature::GetTypeName()返回值找“ExtrudeBoss”和“ExtrudeCut”的区别。车间电脑通常禁用USB、禁用远程桌面、甚至没有管理员权限安装VS,但Word一定有,而且打开就跑。
Word文档的章节编号(第七章、第十章、第十二章)不是随意排的,它严格对应开发者的工作流顺序:
-第七章解决“怎么让模型动起来”——这是所有自动化的基础,没有建模控制,后续BOM、工程图都是空中楼阁;
-第十章解决“怎么让图纸说话”——公差、粗糙度、基准这些非几何信息,才是客户验收时最挑剔的部分;
-第十二章解决“怎么让数据流动起来”——BOM是连接设计、工艺、采购的枢纽,导出质量直接决定下游效率。
每个章节内部,又按“问题场景→API定位→关键参数→避坑提示→完整代码”的逻辑展开。比如第十章讲“形位公差批量修改”,不会先讲IGtol接口继承关系,而是直接抛出场景:“客户要求将所有‘位置度’公差框的公差值从0.2改为0.15,且保持基准字母A/B/C不变”。然后告诉你:第一步,用IDrawingDoc::GetFirstView()遍历视图;第二步,在视图里用IView::GetFirstDrawingNote()找注释;第三步,用IDrawingNote::GetNoteText()判断是否为形位公差;第四步,调用IGtol::SetToleranceValue(0.15)。每一步都附带swNoteText字符串的典型值截图(如“POSITION Ø0.2 | A | B | C”),避免你卡在文本匹配上。
这种设计让文档本身成了一个“可视化调试器”。你不需要运行代码就能预判效果——看到第七章的拉伸特征参数表,你就知道Depth参数单位是米,DraftAngle是弧度制,DraftAlongDirection布尔值设为True时拔模方向才生效。这比在VS里打断点看feature.GetDefinition()返回的对象属性,直观一百倍。
2.3 混合语言支持:VB.NET、C#、Python并存的现实主义选择
资源包里同时存在.vb、.cs、.py文件,这不是炫技,而是覆盖真实产线的技术栈断层。德系车企供应商普遍用VB.NET(历史遗留系统多),日系电子厂倾向C#(.NET生态成熟),而国内中小制造企业越来越多用Python(学习成本低、脚本分发方便)。资料里所有核心功能都提供至少两种语言实现,且保证逻辑完全一致。
以BOM导出为例:
- VB.NET版本用DataTable构建内存表,调用Microsoft.Office.Interop.Excel写入;
- C#版本用EPPlus库(轻量级,无需Office安装)生成.xlsx;
- Python版本用openpyxl,并额外提供pandas兼容接口,方便对接MES系统。
关键不是语法差异,而是错误处理策略的统一。所有版本都强制包含:
' VB.NET 示例:BOM导出中的关键防护 If Not IsNothing(assy) AndAlso assy.GetType() = GetType(IAssemblyDoc) Then ' 安全获取组件 Dim comps As Object = assy.GetComponents(False) If Not IsNothing(comps) AndAlso TypeOf comps Is Array Then For Each comp As IComponent2 In DirectCast(comps, Array) ' 防止空引用异常 If Not IsNothing(comp) AndAlso Not IsNothing(comp.ReferencedModel) Then ' 获取自定义属性 Dim model As IModelDoc2 = comp.ReferencedModel Dim propVal As String = model.CustomInfo2("", "设计者") ' 即使属性为空,也写入空字符串,避免Excel列错位 row("设计者") = If(String.IsNullOrEmpty(propVal), "", propVal) End If Next End If End If这段代码的价值,远超语法本身。它告诉你:SolidWorks API返回的对象,90%概率是Nothing(VB)或null(C#),必须层层判空;GetComponents返回的是Object数组,必须显式转换;自定义属性读取失败时,返回空字符串比抛异常更符合产线稳定需求。这些细节,官方文档永远不会写,但它们决定了你的脚本是在客户电脑上安静运行,还是弹出一个红色错误框毁掉整个演示。
3. 核心细节解析与实操要点:特征树操作、几何元素关联与公差参数化的底层逻辑
当你真正开始写代码,就会发现SolidWorks API里最反直觉的设计,往往藏在最基础的操作里。比如“获取一个面”,你以为调用IFace2接口就行,但实际要经过“特征→实体→面”的三级寻址;再比如“修改尺寸公差”,你以为改IDimension::SetToleranceValue()就够了,却不知道必须先调用IDimension::SetToleranceType(swTolHIDDEN)才能让公差框显示出来。这些坑,资料里都用“实操要点”的形式标出来了。
3.1 特征树操作:为什么IFeature::GetTypeName()比IFeature::Name更可靠
在第七章的特征遍历示例中,核心代码是:
Dim feat As IFeature = model.FirstFeature() Do While Not IsNothing(feat) Dim typeName As String = feat.GetTypeName() ' 关键判断:用typeName而非feat.Name If typeName = "ExtrudeBoss" Or typeName = "ExtrudeCut" Then ' 处理拉伸特征 ProcessExtrudeFeature(feat) ElseIf typeName = "Fillet" Then ' 处理倒圆角 ProcessFilletFeature(feat) End If feat = feat.GetNextFeature() Loop这里必须用GetTypeName(),而不是直接比较feat.Name(比如“拉伸1”、“拉伸2”),原因有三:
名称可变性:用户可以随时在特征树里右键重命名特征,
feat.Name会随之改变,但GetTypeName()永远返回底层特征类型标识符(如“ExtrudeBoss”代表拉伸凸台,“RevolveBoss”代表旋转凸台)。这就像识别一个人,看身份证号比看微信昵称靠谱得多。多语言兼容:SolidWorks界面语言切换时,
feat.Name会变成中文“拉伸1”或英文“Extrude1”,但GetTypeName()始终是英文标识符。我们曾在一个出口模具项目中栽过跟头——客户用德语版SolidWorks,我们的脚本因feat.Name.Contains("Extrude")失效,导致所有拉伸特征被跳过。换成GetTypeName()后,问题瞬间解决。子特征识别:对于复杂特征(如“组合曲线”、“分割线”),
feat.Name可能只是“组合曲线1”,但GetTypeName()返回“CompositeCurve”,这才是你真正要捕获的类型。资料第七章专门有一个表格,列出了200+常用特征类型的TypeName值及其对应中文含义,比如:
| TypeName | 中文特征名 | 典型用途 |
|----------|------------|----------|
|ExtrudeBoss| 拉伸凸台 | 主体结构建模 |
|Chamfer| 倒角 | 边缘处理 |
|Shell| 抽壳 | 薄壁件生成 |
|ReferencePlane| 基准面 | 作为后续建模参考 |
提示:
GetTypeNumber()返回的是整数ID(如swFeatureNameID_e.swExtrudeBoss),但这个枚举值在不同SolidWorks版本中可能变化,而字符串"ExtrudeBoss"是稳定的。所以资料里所有示例都用字符串匹配,而非枚举值比较。
3.2 几何元素关联:面、边、点的“三层寻址”模型
第十章讲工程图公差时,常需要“找到某个尺寸所关联的面”。很多人以为调用IDimension::GetReferencedEntity()就行,结果返回Nothing。真相是:SolidWorks的几何关联是分层的,必须按“特征→实体→面/边/点”的路径逐级获取。
以获取拉伸特征的顶面为例,第七章给出的标准流程是:
' 步骤1:从特征获取定义对象 Dim def As IFeatureDefinition = feat.GetDefinition() If TypeOf def Is IExtrudeFeatureData2 Then Dim extrudeDef As IExtrudeFeatureData2 = DirectCast(def, IExtrudeFeatureData2) ' 步骤2:获取拉伸的起始面(通常是草图所在面) Dim startFace As IFace2 = extrudeDef.GetStartFace() ' 步骤3:如果需要顶面,则获取拉伸结束后的面 ' 注意:必须先调用feat.GetFaces()获取所有面,再筛选 Dim faces As Object = feat.GetFaces() If Not IsNothing(faces) AndAlso TypeOf faces Is Array Then For Each face As IFace2 In DirectCast(faces, Array) ' 判断是否为顶面:法向量Z分量接近1,且面积最大 Dim normal As Double() = face.GetSurface().Normal Dim area As Double = face.GetArea() If Math.Abs(normal(2)) > 0.99 AndAlso area > maxArea Then topFace = face maxArea = area End If Next End If End If这个流程揭示了两个关键实操要点:
GetFaces()返回的是Object数组,不是IFace2数组:必须用DirectCast转换,且要判空。很多初学者直接写For Each face As IFace2 In feat.GetFaces(),结果运行时报“无法将Object转换为IFace2”。面的识别不能只靠名称或序号:SolidWorks不保证
GetFaces()返回的面顺序固定。第七章提供了三种鲁棒识别法:
1.法向量法:计算面法向量,与拉伸方向点积最大者为顶面(适用于规则拉伸);
2.距离法:计算面中心点到拉伸起点的距离,最远者为顶面(适用于斜拉伸);
3.拓扑法:调用face.GetAdjacentFaces(),顶面通常只与侧面相邻,而底面还与草图平面相邻(适用于复杂曲面)。
资料里所有涉及几何元素获取的代码,都内置了这三种方法的开关,你可以根据模型复杂度选择。比如简单箱体用法向量法(快),复杂铸件用拓扑法(准)。
3.3 工程图公差参数化:尺寸公差与形位公差的“双轨制”设置
第十章最常被问的问题是:“为什么我调用IDimension::SetToleranceValue(0.1)后,图纸上公差框还是空的?”答案藏在SolidWorks的公差显示机制里:尺寸公差和形位公差是两套独立系统,必须分别激活。
尺寸公差设置(IDimension体系)
' 正确流程:四步缺一不可 Dim dim As IDimension = view.CreateDrawDimension2(...) ' 创建尺寸 ' 步骤1:设置公差类型(必须!) dim.SetToleranceType(swTolLIMIT) ' 限值公差 ' 步骤2:设置公差值(必须!) dim.SetToleranceValue(0.1) ' 步骤3:设置显示模式(必须!) dim.SetToleranceDisplay(swTolDispSHOW) ' 显示公差框 ' 步骤4:刷新视图(必须!) view.GraphicsRedraw2()漏掉任何一步,公差都不会显示。资料第十章用加粗红字强调:“SetToleranceType是开关,SetToleranceValue是数值,SetToleranceDisplay是显示器电源,三者缺一不可”。
形位公差设置(IGtol体系)
形位公差更复杂,因为它涉及“公差框+基准”两个部分:
' 创建形位公差对象 Dim gtol As IGtol = drawing.CreateDrawGtol2(...) ' 步骤1:设置公差类型(如位置度) gtol.SetGtolType(swGTOLTYPE_POSITION) ' 步骤2:设置公差值(直径符号Ø) gtol.SetToleranceValue(0.15) gtol.SetDiameter(True) ' 步骤3:设置第一基准(A) gtol.SetDatumReference(1, "A") ' 步骤4:设置第二基准(B) gtol.SetDatumReference(2, "B") ' 步骤5:设置第三基准(C) gtol.SetDatumReference(3, "C") ' 步骤6:关联到目标面(必须!否则公差框悬浮) gtol.SetAttachedEntity(targetFace)这里的关键陷阱是SetAttachedEntity()。很多脚本能创建公差框,但框是飘在图纸空白处的,因为没关联到具体面。第十章提供了“面自动匹配算法”:遍历图纸所有视图,对每个视图调用IView::GetVisibleEntities2(swViewEntityType_e.swViewEntityType_Face)获取可见面,再用IFace2::GetClosestPointOn()计算公差框插入点到面的距离,距离最近者即为目标面。
注意:
IGtol::SetDatumReference()的索引从1开始,不是0。设SetDatumReference(0, "A")会静默失败,框里不显示基准字母。这个坑我们踩了三次,资料里用独立警告框标出。
4. 实操过程与核心环节实现:从零开始写一个“一键导出带层级BOM的Excel”脚本
现在,让我们动手实现一个真实产线需求:客户要求将装配体的所有子组件,按装配层级(1级、2级、3级…)导出到Excel,每行包含组件名称、数量、材料、设计者、重量,并自动合并相同组件的行(即“汇总BOM”)。这个功能在第十二章有完整实现,下面我带你一步步走通。
4.1 环境准备:为什么推荐Python + openpyxl而非.NET + Excel Interop
虽然资料提供VB.NET和C#版本,但我个人在产线部署时,100%选择Python,原因很实在:
- 免安装依赖:
openpyxl纯Python库,pip install openpyxl即可,不像Microsoft.Office.Interop.Excel要求目标电脑必须装Office且版本匹配; - 进程隔离:Python脚本运行完自动退出,不会像.NET Interop那样残留Excel进程,导致下次运行报“另一个程序正在使用此文件”;
- 错误容忍高:
openpyxl写入失败时抛明确异常,而Interop经常静默失败,日志里只有一行“HRESULT:0x80010105”。
所以,我们以Python版本为蓝本。首先,requirements.txt内容如下:
pywin32==306 openpyxl==3.1.2注意pywin32版本必须与Python匹配(Python 3.9用306,3.10用307),否则win32com.client.Dispatch("SldWorks.Application")会报“模块未找到”。
4.2 核心代码实现:层级遍历与数据组装
ExportBOMToExcel.py的核心逻辑分三步:连接SolidWorks→遍历装配体→写入Excel。我们重点看第二步“层级遍历”,这是BOM准确性的基石。
import win32com.client from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment def export_bom_to_excel(assembly_path, output_path): # 步骤1:连接SolidWorks(带超时防护) try: swApp = win32com.client.Dispatch("SldWorks.Application") swApp.Visible = False # 后台运行,不干扰用户 except Exception as e: print(f"无法连接SolidWorks: {e}") return # 步骤2:打开装配体(带错误捕获) try: doc = swApp.OpenDoc6(assembly_path, 2, 0, "", 0, 0) # 2=swDocASSEMBLY if doc is None: raise Exception("打开装配体失败,请检查路径和SolidWorks版本") except Exception as e: print(f"打开装配体失败: {e}") return # 步骤3:递归遍历组件(核心!) bom_data = [] def traverse_components(comp, level=1, parent_name=""): """递归遍历组件,level表示层级(1为顶层)""" if comp is None: return # 获取组件基本信息 comp_name = comp.Name2 # Name2比Name更稳定,含配置名 comp_model = comp.ReferencedModel qty = comp.GetSuppression() # 获取抑制状态,用于判断是否计入BOM # 只统计未抑制的组件 if qty != 0: # 0=未抑制,1=抑制,-1=轻化 # 获取模型文档(可能是零件或子装配体) if comp_model is not None: try: # 读取自定义属性(设计者、材料等) props = {} props["名称"] = comp_name props["数量"] = 1 # 初始数量为1,后续按实例数累加 props["层级"] = level # 材料属性(常见属性名) for prop_name in ["材料", "Material", "MATERIAL"]: mat_val = comp_model.CustomInfo2("", prop_name) if mat_val and not mat_val.isspace(): props["材料"] = mat_val.strip() break else: props["材料"] = "" # 设计者属性 designer = comp_model.CustomInfo2("", "设计者") props["设计者"] = designer.strip() if designer else "" # 重量(单位:kg) weight = comp_model.GetMassProperties2(0, None, 0) props["重量(kg)"] = round(weight[0], 3) if weight else 0.0 # 添加到BOM列表 bom_data.append(props.copy()) # 如果是子装配体,递归遍历其组件 if comp_model.GetType() == 2: # 2=swDocASSEMBLY sub_comps = comp_model.GetComponents(False) if sub_comps and hasattr(sub_comps, '__iter__'): for sub_comp in sub_comps: traverse_components(sub_comp, level + 1, comp_name) except Exception as e: print(f"处理组件 {comp_name} 时出错: {e}") # 出错不中断,继续处理下一个组件 # 开始遍历(从顶层装配体开始) try: top_assy = doc if hasattr(top_assy, 'GetComponents'): comps = top_assy.GetComponents(False) if comps and hasattr(comps, '__iter__'): for comp in comps: traverse_components(comp, 1) except Exception as e: print(f"遍历组件时出错: {e}") # 步骤4:写入Excel(openpyxl实现) wb = Workbook() ws = wb.active ws.title = "BOM汇总" # 表头 headers = ["层级", "名称", "数量", "材料", "设计者", "重量(kg)"] for col, header in enumerate(headers, 1): cell = ws.cell(row=1, column=col, value=header) cell.font = Font(bold=True) cell.fill = PatternFill(start_color="CCCCCC", end_color="CCCCCC", fill_type="solid") cell.alignment = Alignment(horizontal="center") # 数据行(按层级排序) bom_data.sort(key=lambda x: x["层级"]) for row_idx, item in enumerate(bom_data, 2): for col_idx, header in enumerate(headers, 1): value = item.get(header, "") ws.cell(row=row_idx, column=col_idx, value=value) # 自动调整列宽 for column in ws.columns: max_length = 0 column_letter = column[0].column_letter for cell in column: try: if len(str(cell.value)) > max_length: max_length = len(str(cell.value)) except: pass adjusted_width = min(max_length + 2, 50) # 最大50字符 ws.column_dimensions[column_letter].width = adjusted_width # 保存 wb.save(output_path) print(f"BOM已导出至: {output_path}") # 清理资源(关键!) swApp.Quit() del swApp, doc, wb # 使用示例 if __name__ == "__main__": assembly_path = r"C:\models\engine_assembly.SLDASM" output_path = r"C:\bom\engine_bom.xlsx" export_bom_to_excel(assembly_path, output_path)这段代码的实操要点,远不止语法本身:
comp.GetSuppression()返回值解读:0=未抑制(计入BOM),1=抑制(跳过),-1=轻化(Lightweight,需先comp.Resolve()才能读取属性)。资料第十二章专门提醒:“轻化组件的ReferencedModel为None,直接访问会崩溃,必须先Resolve()”。CustomInfo2的健壮读取:comp_model.CustomInfo2("", "材料")中第一个参数是配置名,传空字符串""表示读取默认配置。但有些老图纸配置名是"Default",所以第十二章建议加一层fallback:python def get_custom_prop(model, prop_name): val = model.CustomInfo2("", prop_name) if not val or val.isspace(): val = model.CustomInfo2("Default", prop_name) return val.strip() if val else ""重量计算的精度陷阱:
GetMassProperties2()返回的是tuple,索引[0]是质量(kg),但必须传0作为第一个参数(表示使用当前单位系统),否则返回None。这个参数意义在官方文档里藏得很深,资料第十二章用加粗表格列出所有参数含义。
4.3 Excel输出增强:自动合并相同组件与层级缩进
上面代码导出的是“明细BOM”,但客户常要“汇总BOM”(相同零件合并为一行,数量累加)。第十二章提供了merge_bom_items()函数:
from collections import defaultdict def merge_bom_items(bom_data): """合并相同组件(按名称和材料),数量累加""" merged = defaultdict(lambda: {"数量": 0, "重量(kg)": 0.0}) for item in bom_data: # 合并键:名称+材料(忽略空格和大小写) key = f"{item['名称'].strip().lower()}|{item['材料'].strip().lower()}" merged[key]["数量"] += item["数量"] merged[key]["重量(kg)"] += item["重量(kg)"] # 保留其他字段(取第一个出现的值) for field in ["层级", "设计者"]: if field not in merged[key]: merged[key][field] = item[field] # 转回列表 result = [] for key, values in merged.items(): # 解析名称和材料 name_mat = key.split("|") values["名称"] = name_mat[0].title() values["材料"] = name_mat[1].upper() if len(name_mat) > 1 else "" result.append(values) return result更绝的是层级缩进显示:在Excel里,2级组件名称前加两个空格,3级加四个,以此类推。第十二章的write_bom_with_indent()函数这样实现:
def write_bom_with_indent(ws, bom_data, start_row=2): for idx, item in enumerate(bom_data, start_row): # 名称列添加缩进空格 indented_name = " " * (item["层级"] - 1) + item["名称"] ws.cell(row=idx, column=2, value=indented_name) # 其他列正常写入 ws.cell(row=idx, column=1, value=item["层级"]) ws.cell(row=idx, column=3, value=item["数量"]) # ... 其他列这样导出的Excel,一眼就能看出装配结构,比纯文字描述直观十倍。
5. 常见问题与排查技巧实录:那些让SolidWorks二次开发者彻夜难眠的真问题
在产线调试中,90%的问题不是代码写错,而是SolidWorks API的“隐性契约”没被满足。这些问题不会报错,只会让你的脚本静默失效,或者在客户电脑上表现诡异。以下是资料里整理的“高频致郁问题”及独家排查法。
5.1 “脚本在自己电脑上好好的,到客户电脑就崩溃”——COM权限与版本错配
现象:你的ExportBOMToExcel.py在开发机(SolidWorks 2022)上运行完美,但拷贝到客户车间电脑(SolidWorks 2018)后,win32com.client.Dispatch("SldWorks.Application")直接抛pywintypes.com_error。
根因:pywin32的COM接口绑定是版本敏感的。Dispatch("SldWorks.Application")会尝试连接最新注册的SolidWorks版本,但如果客户电脑装了多个版本(如2018和2022),注册表里可能指向2022,而你的脚本调用了2022特有的API(如IAssemblyDoc::GetComponents2()),在2018上就不存在。
排查技巧:
1. 在客户电脑上,打开SolidWorks,按Ctrl+Shift+Alt+D打开API诊断窗口,查看当前版本号;
2. 在Python中,用swApp.GetVersion()获取运行时版本,与预期对比;
3.终极方案:不Dispatch,而用GetActiveObject连接已打开的SolidWorks实例:python try: # 尝试连接已打开的SolidWorks swApp = win32com.client.GetActiveObject("SldWorks.Application") except: # 如果没打开,再Dispatch swApp = win32com.client.Dispatch("SldWorks.Application")
这样脚本总是连接客户正在用的版本,杜绝错配。
5.2 “特征树遍历漏掉了某些特征”——隐藏特征与轻化状态的识别盲区
现象:第七章的特征遍历代码,运行后只找到了“拉伸1”、“倒角1”,但图纸里明明还有“镜像1”、“圆角1”。
根因:model.FirstFeature()只返回可见且未轻化的特征。被抑制(Suppressed)或轻化(Lightweight)的特征,不会出现在遍历链中。
排查技巧:
-检查抑制状态:在SolidWorks中,特征树里被抑制的特征带(S)标记,轻化特征带(L)标记;
-强制加载轻化特征:在遍历前,调用model.ResolveAllLightweightComponents();
-遍历所有特征(包括抑制的):用model.FeatureByPositionReverse()从末尾往前遍历,配合feat.GetSuppression()判断状态:vb Dim featCount As Integer = model.GetFeatureCount2(True) ' True=包含抑制特征 For i As Integer = featCount To 1 Step -1 Dim feat As IFeature = model.FeatureByPositionReverse(i) If Not IsNothing(feat) Then Dim sup As Integer = feat.GetSuppression() If sup = 0 Then ' 未抑制 ProcessFeature(feat) ElseIf sup = -1 Then ' 轻化 feat.Resolve() ' 强制加载 ProcessFeature(feat) End If End If Next
5.3 “工程图尺寸公差改了,但图纸没刷新”——GraphicsRedraw2()的调用时机陷阱
现象:第十章的公差修改脚本,运行后尺寸值变了,但公差框还是旧的,甚至整个视图一片灰。
根因:view.GraphicsRedraw2()必须在所有修改操作完成后调用,且必须针对正确的视图对象。常见错误:
- 在循环里每次修改一个尺寸就调用一次GraphicsRedraw2(),导致性能暴跌;
- 调用了model.GraphicsRedraw2()(整个模型重绘),但工程图修改必须用view.GraphicsRedraw2();
- 修改了尺寸,但没调用view.Activate()激活视图。
排查技巧:
-批量刷新:所有尺寸修改完成后,再统一调用一次view.GraphicsRedraw2();
-视图激活保障:在修改前,确保视图是激活的:vb view.Activate() ' 修改尺寸... view.GraphicsRedraw2()
-强制重绘备选:如果GraphicsRedraw2()无效,用swApp.CommandInProgress = True触发强制刷新(资料第十章称之为“API急救针”)。
5.4 “BOM导出的重量全是0”——单位系统与质量属性计算的隐藏开关
现象:第十二章的BOM脚本,导出的“重量(kg)”列全是0.0,但SolidWorks里用“评估→质量属性”能看到正确数值。
根因:GetMassProperties2()需要模型已计算过质量属性。新打开的模型,或刚修改过的模型,质量属性缓存可能未更新。
排查技巧:
-强制更新质量属性:在调用GetMassProperties2()前,先调用model.ForceRebuild3(False);
-检查单位系统:GetMassProperties2()返回的质量单位,取决于SolidWorks当前单位系统。如果单位设为“毫米”,质量单位是tonnes(吨),不是kg!必须用swApp.GetUserPreferenceIntegerValue(swUserPreferenceIntegerValue_e.swUnitSystem)获取当前单位,再换算:vb Dim unitSys As Integer = swApp.GetUserPreferenceIntegerValue(12) ' swUnitSystem Dim mass As Double = weight(0) If unitSys = 0 Then ' MMGS (mm, gram, second) mass = mass / 1000 ' 转kg ElseIf unitSys = 1 Then ' IPS (inch, pound, second) mass = mass * 0.45359237 ' 转kg End If
实操心得:在资料第十二章的BOM脚本开头,我加了一行
swApp.SetUserPreferenceIntegerValue(swUserPreferenceIntegerValue_e.swUnitSystem, 0),强制切到MMGS单位,避免单位混乱。这是产线部署时最省心的做法。
6. 附录:各章节核心能力速查表与避坑清单
为了让你在调试时能快速定位,我把资料里最常被翻阅的章节精华,浓缩成一张速查表。这不是功能罗列,而是“你遇到这个问题时,该翻哪一章、看哪个小节、注意什么坑”的实战导航。
| 问题场景 | 对应章节 | 关键小节 | 必读避坑提示 | 典型代码片段位置 |
|---|---|---|---|---|
| 想自动创建一个带拔模的拉伸凸台 | 第七章 | 7.3 拉伸特征参数化 | IDraftAngle必须用弧度制;DraftAlongDirection=True才启用拔模;拔模方向向量必须单位化 | CreateExtrudeBossFeature.vb第42行 |
| 批量修改50张图的尺寸公差值 | 第十章 | 10.2 尺寸公差批量设置 | SetToleranceType()、SetToleranceValue()、SetToleranceDisplay()三者缺一不可;修改后必须view.GraphicsRedraw2() | BatchModifyTolerance.py第88行 |
| 导出BOM时“设计者”列全是#N/A | 第十二章 | 12.4 自定义属性读取 | CustomInfo2("", "设计者")中第一个参数为空字符串;若读不到,尝试CustomInfo2("Default", "设计者");轻化组件需先Resolve() | ExportBOMToExcel.cs第156行 |
| 遍历装配体时漏掉了子装配体里的零件 | 第十二章 | 12.2 层级遍历递归 | GetComponents(False)只返回顶层组件;子装配体需调用ReferencedModel.GetComponents(False)递归;轻化子装配体必须先Resolve() | ExportBOMToExcel.py第73行 |
| 脚本运行后SolidWorks卡死无响应 | 通用 | 附录A 资源释放规范 | 所有win32com对象必须显式del;Marshal.ReleaseComObject()在.NET中必须调用;Python中用del后加gc.collect() | 所有.py文件结尾处 |
这张表的每一项,都来自真实踩坑记录。比如“BOM设计者列#N/A”问题,我们曾在一个航空结构件项目中耗时两天排查——最终发现客户图纸的自定义属性配置名是"Designer"而非"设计者",且部分老图纸属性存储在配置"AeroConfig"里。资料第十章为此专门增加了“多语言属性名映射表”,列出了中/英/德/日语环境下最常见的12个属性名变体。
最后分享一个小技巧:资料里所有Word文档的页眉,都印着章节编号和最后更新日期(如“第七章 · 2024-03-15”)。这不是形式主义,而是告诉你:这个功能模块,是在哪个SolidWorks版本、哪个Windows系统上实测通过的。当你在客户电脑上遇到问题,先看页眉日期——如果文档是2023年更新的,而客户用的是SolidWorks 2024,那大概率需要检查API变更日志。这种细节,只有真正天天泡在产线的人,才会觉得珍贵。
我在车间电脑旁贴了一张便签,上面写着:“别信文档,信日志;别信理论,信F5”。这套资料,就是我过去三年所有F5失败的日志,熬成的结晶。
本文还有配套的精品资源,点击获取
简介:这套SolidWorks二次开发资料以实际功能落地为导向,覆盖开发环境配置、常用API类结构与继承关系理解、文档新建/打开/保存等基础操作。重点讲解特征管理器遍历、特征树节点操作,以及拉伸、倒角、倒圆角等核心建模命令的程序化调用方法;提供面、边、顶点等几何元素的获取路径与关联逻辑。装配体部分支持组件遍历、属性读取及BOM表格一键导出为Excel格式。工程图模块聚焦自动化编辑能力,包括视图中尺寸显示控制、前缀后缀批量修改、尺寸公差与形位公差的参数化设置、表面粗糙度符号插入、基准目标标注、技术要求注释等内容的脚本化处理。所有内容按功能模块分章组织,如第七章详解建模特征编程,第十章集中说明工程图注释与公差控制策略,第十二章梳理装配体组件操作与BOM生成流程,每章对应可直接参考的Word文档,编号清晰、接口调用示例明确,便于开发者快速定位并复用代码逻辑。
本文还有配套的精品资源,点击获取