简介:《CAD-VBA开发人员手册》是面向AutoCAD二次开发初学者与进阶VBA开发者编写的技术指南,作者解祥成。全书共十章,从VBA入门、嵌入与全局工程组织、宏处理讲起,逐步深入ActiveX自动操作基础、AutoCAD对象模型与集合对象操作,再到控制AutoCAD环境、创建编辑图元、标注与公差、菜单工具栏定制、事件处理、三维空间建模、布局打印及高级绘图组织技术,覆盖从基础到高级的完整知识链路。资源包为1个PDF文件,大小约3.16MB,目录结构清晰,便于按章节检索学习。目前已有2488人学习下载,适合希望系统掌握VBA驱动AutoCAD自动化、提升绘图效率与项目实施能力的开发者参考。
1. CAD-VBA开发人员手册:从翻手册到写出能跑的生产脚本
很多人第一次打开《CAD-VBA开发人员手册》这类资料时,心态是把它当字典查——遇到问题翻一翻,抄一段代码改改就用。但真正在产线上写过批量出图、自动标注、图纸合并脚本的人都知道,手册只是起点,真正的门槛在于:你能否把手册里的对象模型、事件、方法,组合成一个能稳定跑完几百张图纸、不崩、不丢数据、还能被同事复用的工具。CAD 二次开发这件事,AutoCAD、中望 CAD、浩辰 CAD 都支持 VBA,语法几乎一致,差异主要在对象库版本和少量 API 上。这篇笔记面向两类人:一类是刚接触 VBA、想从“录制宏”进阶到“手写脚本”的 CAD 制图人员;另一类是有编程基础、但没系统做过 CAD 对象模型开发的工程师。我会按“手册怎么读 → 环境怎么搭 → 核心对象怎么用 → 批量任务怎么写 → 坑在哪 → 怎么验证”的顺序,把这条路径讲透,让你看完能直接动手写自己的第一个生产级脚本。
2. 手册的正确打开方式:对象模型、事件与代码骨架
2.1 先搞懂 Application / Document / ModelSpace 三层结构
《CAD-VBA开发人员手册》里最核心的一张图,就是 AutoCAD 的对象模型树。很多人翻手册只查方法名,结果写出来的代码逻辑混乱,根本原因是没建立层级概念。VBA 操作 CAD,永远是从ThisDrawing或Application往下走:
Application:代表 CAD 程序本身,管全局设置、打开文档、执行命令。Document:代表一个打开的 dwg 文件,管图层、块表、选择集。ModelSpace/PaperSpace:模型空间和布局空间,管图元实体。
一个典型的骨架长这样:
Sub BatchProcess() Dim acadApp As AcadApplication Dim acadDoc As AcadDocument Dim ms As AcadModelSpace ' 获取当前运行的 CAD 实例 Set acadApp = ThisDrawing.Application Set acadDoc = acadApp.ActiveDocument Set ms = acadDoc.ModelSpace ' 在这里写你的业务逻辑 Dim ent As AcadEntity For Each ent In ms ' 遍历模型空间所有实体 Debug.Print ent.ObjectName Next ent End Sub这段代码的逻辑说明:ThisDrawing是 VBA 在 CAD 环境里的全局入口,等价于Application.ActiveDocument。ModelSpace是一个集合对象,支持For Each遍历。参数说明:ObjectName返回实体的类型字符串,比如AcDbLine、AcDbCircle、AcDbBlockReference,这是你后续做条件筛选的依据。新手常犯的错是直接对ThisDrawing调方法,而不区分当前文档和全局应用,导致多文档场景下操作错文件。
2.2 事件驱动:为什么你的脚本要挂在 Document 上
手册里有一章专门讲事件,很多人跳过,结果写出来的工具只能手动运行。真正好用的 CAD 插件,往往是在Document_Open、Document_Close、Object_Modified这些事件上挂逻辑。比如图纸合并场景,你可以在打开每张图纸时自动收集图框信息,而不是等用户手动点按钮。
' 在 ThisDrawing 的代码模块中写 Private Sub Document_Open() Dim layer As AcadLayer ' 打开图纸时自动检查图层规范 For Each layer In ThisDrawing.Layers If layer.Name Like "TEMP_*" Then layer.LayerOn = False End If Next layer End Sub逻辑说明:Document_Open是文档级事件,只有写在ThisDrawing模块里才生效。参数说明:LayerOn控制图层开关,Like "TEMP_*"是 VBA 的通配符匹配。注意,事件代码如果报错,CAD 不会弹窗提示,而是静默失败,所以调试时要在关键位置加On Error Resume Next配合日志输出。
2.3 用字典和数组管理数据,别用单元格
热搜里vba字典、vba数组出现频率很高,说明很多人卡在数据组织上。CAD 脚本经常要处理“图层名 → 数量”“块名 → 插入点列表”这类映射关系。用 Excel 单元格存中间结果,速度慢且容易丢。正确做法是用Scripting.Dictionary和动态数组。
Dim dict As Object Set dict = CreateObject("Scripting.Dictionary") Dim ent As AcadEntity For Each ent In ThisDrawing.ModelSpace If TypeOf ent Is AcadBlockReference Then Dim blkName As String blkName = ent.Name If dict.Exists(blkName) Then dict(blkName) = dict(blkName) + 1 Else dict.Add blkName, 1 End If End If Next ent ' 输出统计结果 Dim key As Variant For Each key In dict.Keys Debug.Print key & ": " & dict(key) Next key逻辑说明:CreateObject("Scripting.Dictionary")是后期绑定,不需要额外引用。参数说明:Exists判断键是否存在,Keys返回所有键的数组。这段代码统计模型空间里每种块的插入次数,是图纸合并、BOM 导出类脚本的基础。注意TypeOf ent Is AcadBlockReference比ent.ObjectName = "AcDbBlockReference"更可靠,因为前者是类型判断,后者是字符串比较。
3. 环境搭建与第一个可运行脚本:从引用库到调试输出
3.1 VBA 编辑器入口与引用设置
AutoCAD 里按Alt + F11打开 VBA 编辑器,中望 CAD 和浩辰 CAD 也是同样的快捷键。第一次写代码前,必须检查“工具 → 引用”里有没有勾选对应的类型库。常见的有:
| 引用名称 | 用途 | 是否必须 |
|---|---|---|
| AutoCAD 20xx Type Library | 核心对象模型 | 是 |
| Visual Basic For Applications | 基础运行时 | 默认勾选 |
| Microsoft Scripting Runtime | 字典对象 | 建议勾选 |
| Microsoft Excel xx Object Library | 读写 Excel | 按需 |
如果引用列表里找不到 AutoCAD 库,说明 CAD 安装不完整,或者你打开的是独立 VBA 编辑器而非 CAD 内嵌的。热搜里cad安装、cad卸载工具相关的问题,很多最后都追溯到 VBA 组件缺失。一个稳妥的修复方式是重新运行 CAD 安装程序,勾选 VBA 组件。
3.2 写一个“统计当前图纸所有直线总长度”的脚本
这是最经典的入门练习,能覆盖选择集、遍历、属性读取、单位换算。
Sub CountLineLength() Dim ss As AcadSelectionSet Dim ent As AcadEntity Dim totalLen As Double Dim lineCount As Long ' 删除同名选择集,避免重复创建报错 On Error Resume Next ThisDrawing.SelectionSets("MySS").Delete On Error GoTo 0 Set ss = ThisDrawing.SelectionSets.Add("MySS") ' 筛选直线:DXF 组码 0 表示实体类型 Dim filterType(0) As Integer Dim filterData(0) As Variant filterType(0) = 0 filterData(0) = "LINE" ss.Select acSelectionSetAll, , , filterType, filterData totalLen = 0 lineCount = 0 For Each ent In ss totalLen = totalLen + ent.Length lineCount = lineCount + 1 Next ent MsgBox "直线数量:" & lineCount & vbCrLf & _ "总长度:" & Format(totalLen, "0.00") & " 图形单位" ss.Delete End Sub逻辑说明:SelectionSets.Add创建选择集,Select acSelectionSetAll选中全图,后面两个数组是 DXF 筛选条件。参数说明:filterType(0) = 0表示按实体类型筛选,filterData(0) = "LINE"表示只选直线。ent.Length是 AcadLine 的属性,返回图形单位长度。注意,如果图纸里有块内直线,这段代码不会统计,因为选择集只遍历模型空间顶层实体。要统计块内,需要递归遍历块定义。
3.3 调试输出与错误捕获
VBA 的调试手段有限,Debug.Print输出到“立即窗口”,MsgBox会阻塞执行。生产脚本里我一般用日志文件:
Sub WriteLog(msg As String) Dim fso As Object Dim ts As Object Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.OpenTextFile("C:\temp\cad_vba_log.txt", 8, True) ts.WriteLine Now & " - " & msg ts.Close End Sub逻辑说明:OpenTextFile第二个参数8表示追加模式,第三个参数True表示文件不存在时创建。参数说明:日志路径建议放在临时目录,避免权限问题。错误捕获用On Error GoTo ErrorHandler,在标签处记录Err.Description和Err.Number,然后Resume Next继续执行,不要让一个错误中断整个批量任务。
4. 批量任务实战:图纸合并、批量打印与数据导出
4.1 图纸合并:遍历文件夹、插入块、统一图层
热搜里cad图纸合并是高频需求。常见做法是:遍历指定文件夹下所有 dwg,把每张图的图框和标题栏作为块插入到主图纸的布局中。核心代码:
Sub MergeDrawings(folderPath As String) Dim fso As Object, fld As Object, fil As Object Dim insPt(0 To 2) As Double Dim doc As AcadDocument Set fso = CreateObject("Scripting.FileSystemObject") Set fld = fso.GetFolder(folderPath) Dim yOffset As Double yOffset = 0 For Each fil In fld.Files If LCase(fso.GetExtensionName(fil.Name)) = "dwg" Then insPt(0) = 0: insPt(1) = yOffset: insPt(2) = 0 ' 以块参照方式插入整张图纸 Dim blkRef As AcadBlockReference Set blkRef = ThisDrawing.ModelSpace.InsertBlock( _ insPt, fil.Path, 1#, 1#, 1#, 0) yOffset = yOffset + 500 ' 每张图间隔 500 单位 End If Next fil ThisDrawing.Regen acAllViewports End Sub逻辑说明:InsertBlock把外部 dwg 作为块插入,参数依次是插入点、文件路径、XYZ 缩放比例、旋转角度。参数说明:yOffset控制纵向排列间距,根据图框高度调整。注意,插入的块会继承源图纸的图层,如果源图纸图层不规范,主图纸会变得很乱。稳妥做法是插入前用Layer对象统一重命名或合并图层。
4.2 批量打印:用布局和打印配置批量输出 PDF
热搜里cad转pdf和cad批量打印经常一起出现。VBA 可以通过Plot对象批量输出,但配置项多,容易翻车。
Sub BatchPlotToPDF() Dim layout As AcadLayout Dim plot As AcadPlot Set plot = ThisDrawing.Plot For Each layout In ThisDrawing.Layouts ' 配置打印参数 plot.SetLayoutsToPlot Array(layout.Name) plot.PlotToFile "C:\output\" & layout.Name & ".pdf" Next layout End Sub逻辑说明:SetLayoutsToPlot指定要打印的布局,PlotToFile输出到文件。参数说明:输出路径必须提前创建,否则报错。打印配置(纸张大小、打印样式)需要在布局里预先设好,VBA 只负责触发。常见坑是打印样式表ctb文件路径不对,导致输出全黑或线宽丢失。
4.3 数据导出:把块属性写到 Excel
BOM 导出是 CAD-VBA 最典型的应用。热搜里catia vba 导出bom开源代码说明这个需求跨软件存在。AutoCAD 里用块属性提取:
Sub ExportBlockAttrs() Dim xlApp As Object, xlWb As Object, xlWs As Object Dim ent As AcadEntity Dim row As Long Set xlApp = CreateObject("Excel.Application") Set xlWb = xlApp.Workbooks.Add Set xlWs = xlWb.Sheets(1) row = 1 ' 写表头 xlWs.Cells(row, 1) = "块名" xlWs.Cells(row, 2) = "属性标签" xlWs.Cells(row, 3) = "属性值" row = row + 1 For Each ent In ThisDrawing.ModelSpace If TypeOf ent Is AcadBlockReference Then Dim attrs As Variant attrs = ent.GetAttributes Dim i As Long For i = LBound(attrs) To UBound(attrs) xlWs.Cells(row, 1) = ent.Name xlWs.Cells(row, 2) = attrs(i).TagString xlWs.Cells(row, 3) = attrs(i).TextString row = row + 1 Next i End If Next ent xlWb.SaveAs "C:\output\bom.xlsx" xlApp.Quit Set xlApp = Nothing End Sub逻辑说明:GetAttributes返回块参照的属性数组,每个元素有TagString和TextString。参数说明:LBound和UBound处理数组边界,避免越界。注意 Excel 进程要及时退出,否则后台会残留大量 EXCEL.EXE。
5. 避坑与排查:VBA 在 CAD 里最容易翻车的 5 个场景
5.1 现象:脚本运行到一半卡死,CAD 无响应
原因:在遍历大量实体时频繁调用Regen或Update,或者选择集没有及时释放。解决:把Regen移到循环外,选择集用完后Delete,大循环里加DoEvents让 CAD 处理消息队列。
5.2 现象:ThisDrawing报“对象变量未设置”
原因:代码写在标准模块里,但ThisDrawing只在文档模块(ThisDrawing)中有效。解决:把过程移到ThisDrawing模块,或者改用Application.ActiveDocument。
5.3 现象:中望 CAD 里能跑,AutoCAD 里报错
原因:对象库版本差异,某些属性或方法在低版本不存在。解决:用On Error Resume Next包裹版本敏感代码,或者用Application.Version判断版本号后分支执行。
5.4 现象:批量处理时内存持续增长,最后崩溃
原因:没有释放对象引用,尤其是AcadDocument、SelectionSet、Excel.Application。解决:每个循环结束后Set obj = Nothing,Excel 进程用Quit后确认退出。
5.5 现象:打印输出空白或线条缺失
原因:打印样式表路径错误,或者布局的PlotType设置不对。解决:检查Plot.Configuration和Plot.StyleSheet,确保指向有效的 ctb 文件,打印前用Plot.DisplayPlotPreview预览。
6. 进阶技巧:用类模块封装工具,让脚本可复用可分发
写到一定阶段,你会发现每个脚本都在重复“获取文档、遍历实体、写日志”这些逻辑。这时候该上类模块了。我一般会建一个CadTool类,把常用操作封装成方法:
' 类模块 CadTool Private m_Doc As AcadDocument Public Property Set Document(doc As AcadDocument) Set m_Doc = doc End Property Public Function GetAllEntities() As Collection Dim col As New Collection Dim ent As AcadEntity For Each ent In m_Doc.ModelSpace col.Add ent Next ent Set GetAllEntities = col End Function Public Sub Log(msg As String) ' 日志逻辑 End Sub逻辑说明:Property Set允许外部注入文档对象,GetAllEntities返回 Collection 而不是数组,方便后续扩展。参数说明:类模块要导出为.cls文件,配合.bas模块一起分发。如果要做成 exe 小工具,可以用 VB6 或 VB.NET 包装,但纯 VBA 方案更适合内部分发。
验证方法:写一个测试过程,创建CadTool实例,注入当前文档,调用GetAllEntities并统计数量,和手动选择集结果对比。如果一致,说明封装正确。
我自己的习惯是:每写一个新脚本,先花十分钟把重复逻辑抽到类模块里,哪怕一开始只有两个方法。三个月后回头看,这些类模块就是你的私人手册,比任何 PDF 都管用。希望帮到你。
本文还有配套的精品资源,点击获取