VBA实现Excel与CAD表格互转
▎案例需求
最近换了工作,专职给单位做VBA开发的。很幸运,领导很重视利用VBA来提高效率,实现一些办公流程的自动化。其中有一项内容就是利用Excel数据批量绘制CAD图纸。
关于CAD VBA的东西,会更新几篇,也是作为自己的备忘。本篇文章更新Excel与CAD表格互相导出导入。
▎具体效果(Excel表格导入CAD)
支持合并单元格,如需更细致的需求,需要修改代码相应部分。

▎详细源代码(Excel表格导入CAD)
窗体源代码都在这里,源文件我就不放了。VB画个窗体还是轻轻松松的。

Option ExplicitPrivate Sub cmdCancel_Click()Unload MeEnd SubPrivate Sub cmdOK_Click()On Error Resume Next'获取插入点坐标Dim ptInsert(2) As DoubleptInsert(0) = txtX.Text: ptInsert(1) = txtY.Text: ptInsert(2) = 0'获取并连接当前但开的excel程序及当前表Dim excelApp As ObjectDim excelSheet As ObjectSet excelApp = GetObject(, "excel.application")If Err <> 0 ThenMsgBox "Excel程序未运行,请打开Excel程序!"Err.ClearExit SubEnd IfSet excelSheet = excelApp.activesheet'保存要转化的区域Dim ranges As ObjectIf optAll.Value = True ThenSet ranges = excelSheet.usedrangeElseIf optSelect = True ThenSet ranges = excelApp.SelectionEnd If'对每个单元进行操作Dim excelRg As ObjectFor Each excelRg In rangesaddTableAndText ranges, excelRg, ptInsertNext excelRg'释放Excel对象Set excelSheet = NothingSet excelApp = NothingEnd Sub'转化表格的函数Public Function addTableAndText(ByVal ranges As Object, ByVal excelRg As Object, ByVal ptInsert As Variant)'声明一个AcadLine对象,以便后续对其处理Dim objLine As AcadLine'声明四个坐标变量Dim ptLT(2) As DoubleDim ptLB(2) As DoubleDim ptRT(2) As DoubleDim ptRB(2) As Double'声明一个单元格对象来求顶点坐标Dim rg11 As ObjectSet rg11 = excelRg.Offset(1, 1)'获取四个顶点的坐标ptLT(0) = ptInsert(0) + excelRg.Left * 0.8 - ranges.Left * 0.8ptLT(1) = ptInsert(1) - (excelRg.top - ranges.top)ptLT(2) = 0ptRB(0) = ptInsert(0) + rg11.Left * 0.8 - ranges.Left * 0.8ptRB(1) = ptInsert(1) - (rg11.top - ranges.top)ptRB(2) = 0ptLB(0) = ptLT(0)ptLB(1) = ptRB(1)ptLB(2) = 0ptRT(0) = ptRB(0)ptRT(1) = ptLT(1)ptRT(2) = 0'左侧线If excelRg.Column = ranges.Column And excelRg.borders.Item(1).linestyle > 0 ThenSet objLine = ThisDrawing.ModelSpace.AddLine(ptLT, ptLB)setTableColor objLine, excelRg.borders.Item(1).colorEnd If'右侧线If excelRg.borders.Item(2).linestyle > 0 ThenSet objLine = ThisDrawing.ModelSpace.AddLine(ptRT, ptRB)setTableColor objLine, excelRg.borders.Item(2).colorEnd If'上边线If excelRg.row = ranges.row And excelRg.borders.Item(3).linestyle > 0 ThenSet objLine = ThisDrawing.ModelSpace.AddLine(ptLT, ptRT)setTableColor objLine, excelRg.borders.Item(3).colorEnd If'下边线If excelRg.borders.Item(4).linestyle > 0 ThenSet objLine = ThisDrawing.ModelSpace.AddLine(ptLB, ptRB)setTableColor objLine, excelRg.borders.Item(4).colorEnd If'添加文字Dim objText As AcadTextSet objText = ThisDrawing.ModelSpace.AddText(excelRg.Text, ptLB, excelRg.Font.Size * 0.9)'设置文字的颜色setTextColor objText, excelRg.Font.color'设置文字的对其方式setTextAlignMent objText, ptLT, ptRBEnd Function'改变表格的颜色Public Function setTableColor(ByVal objEntity As AcadEntity, ByVal color As Long)If optTableColor2.Value = True ThenIf cmbTableColor.Text = "By Layer" ThenExit FunctionElseIf cmbTableColor.Text = "红色" ThenobjEntity.color = acRedElseIf cmbTableColor.Text = "绿色" ThenobjEntity.color = acGreenElseIf cmbTableColor.Text = "蓝色" ThenobjEntity.color = acBlueEnd IfExit FunctionEnd IfDim colorR As LongDim colorG As LongDim colorB As LongIf optTableColor1.Value = True ThenIf color <> 0 ThenDim entityColor As AcadAcCmColorSet entityColor = AcadApplication.GetInterfaceObject("AutoCAD.AcCmColor.19")colorR = color And 255colorG = (color And 65280) / 256colorB = (color And 16711680) / 65536entityColor.SetRGB colorR, colorG, colorBobjEntity.TrueColor = entityColorEnd IfEnd IfEnd Function'改变文字的颜色Public Function setTextColor(ByVal objEntity As AcadEntity, ByVal color As Long)If optTextColor2.Value = True ThenIf cmbTextColor.Text = "By Layer" ThenExit FunctionElseIf cmbTextColor.Text = "红色" ThenobjEntity.color = acRedElseIf cmbTextColor.Text = "绿色" ThenobjEntity.color = acGreenElseIf cmbTextColor.Text = "蓝色" ThenobjEntity.color = acBlueEnd IfExit FunctionEnd IfDim colorR As LongDim colorG As LongDim colorB As LongIf optTextColor1.Value = True ThenIf color <> 0 ThenDim entityColor As AcadAcCmColorSet entityColor = AcadApplication.GetInterfaceObject("AutoCAD.AcCmColor.19")colorR = color And 255colorG = (color And 65280) / 256colorB = (color And 16711680) / 65536entityColor.SetRGB colorR, colorG, colorBobjEntity.TrueColor = entityColorEnd IfEnd IfEnd Function'文字的对齐Public Function setTextAlignMent(ByVal objText As AcadText, ByVal ptLT As Variant, ByVal ptRB As Variant)Dim ptMC(2) As DoubleptMC(0) = (ptLT(0) + ptRB(0)) / 2ptMC(1) = (ptLT(1) + ptRB(1)) / 2ptMC(2) = 0If optTextAlignment1.Value = True ThenobjText.Alignment = acAlignmentMiddleCenterobjText.Move objText.TextAlignmentPoint, ptMCExit FunctionEnd IfDim ptML(2) As DoubleptML(0) = ptLT(0)ptML(1) = (ptLT(1) + ptRB(1)) / 2ptML(2) = 0If optTextAlignment2.Value = True ThenobjText.Alignment = acAlignmentMiddleLeftobjText.Move objText.TextAlignmentPoint, ptMLExit FunctionEnd IfDim ptMR(2) As DoubleptMR(0) = ptRB(0)ptMR(1) = (ptLT(1) + ptRB(1)) / 2ptMR(2) = 0If optTextAlignment3.Value = True ThenobjText.Alignment = acAlignmentMiddleRightobjText.Move objText.TextAlignmentPoint, ptMREnd IfEnd FunctionPrivate Sub cmdPickPoint_Click()On Error Resume NextDim pt As VariantUserForm1.Hidept = ThisDrawing.Utility.GetPoint(, "请选择插入点:")txtX.Text = pt(0): txtY.Text = pt(1)UserForm1.showEnd Sub'设置下拉框的内容Public Function addCombbox()cmbTableColor.AddItem "By Layer"cmbTableColor.AddItem "红色"cmbTableColor.AddItem "绿色"cmbTableColor.AddItem "蓝色"cmbTextColor.AddItem "By Layer"cmbTextColor.AddItem "红色"cmbTextColor.AddItem "绿色"cmbTextColor.AddItem "蓝色"End FunctionPrivate Sub optTableColor1_Change()If optTableColor1.Value = True ThencmbTableColor.Enabled = FalsecmbTableColor.Text = ""End IfEnd SubPrivate Sub optTableColor2_Click()If optTableColor2.Value = True ThencmbTableColor.Enabled = TruecmbTableColor.Text = "By Layer"End IfEnd SubPrivate Sub optTextColor1_Change()If optTextColor1.Value = True ThencmbTextColor.Enabled = FalsecmbTextColor.Text = ""End IfEnd SubPrivate Sub optTextColor2_Change()If optTextColor2.Value = True ThencmbTextColor.Enabled = TruecmbTextColor.Text = "By Layer"End IfEnd SubPrivate Sub UserForm_Initialize()txtX.Text = 0: txtY.Text = 0optAll.Value = TrueoptTableColor1.Value = TrueoptTextColor1.Value = TrueaddCombboxoptTextAlignment1.Value = TrueEnd Sub
▎具体效果(CAD表格导入Excel)
支持合并单元格,如需更细致的需求,需要修改代码相应部分。

▎详细源代码(CAD表格导入Excel)
由于涉及到类代码,这里放个代码截图。


Dim dicHorizontalLine As VariantDim dicVerticalLine As VariantDim arrText() As CTextDim fileConst WRITE_LOG = 0Dim WorkDrawingSub ReadTable()"Type;Object;TagID;Position;Track;Segment;Accuracy;Note;SetupOffset"SelectionName = "ss1"Dim sset As AcadSelectionSetDim element As AcadEntityFor Each sset In ThisDrawing.SelectionSetsIf sset.Name = SelectionName Thensset.DeleteExit ForEnd IfNextErase arrTextSet dicHorizontalLine = CreateObject("Scripting.Dictionary")Set dicVerticalLine = CreateObject("Scripting.Dictionary")dicText = CreateObject("Scripting.Dictionary")Dim txt As AcadTextDim txtNum As IntegertxtNum = 0Set sset = ThisDrawing.SelectionSets.Add(SelectionName)Dim objType As Stringsset.SelectOnScreenIf sset.Count > 0 ThenFor Each element In ssetobjType = element.ObjectNameSelect Case objTypeCase "AcDbLine"AddLine element.StartPoint, element.EndPointCase "AcDbText"Set txt = elementIf 1 ThenOn Error Resume NexttxtNum = UBound(arrText)End IftxtNum = txtNum + 1ReDim Preserve arrText(1 To txtNum)Set arrText(txtNum) = New CText= txt.TextStringDim MinPoint, MaxPointMinPoint, MaxPointMaxPointMinPoint'GetBoundingBoxEnd SelectNextIf WRITE_LOG = 1 ThenSaveLines dicHorizontalLine, "Horizontal"SaveLines dicVerticalLine, "Vertical"Dim fsObjSet fsObj = CreateObject("Scripting.FileSystemObject")Set file = fsObj.CreateTextFile(ThisDrawing.Path & "\debug.csv", True)"Remove Horizontal..."End IfRemoveShortLines dicHorizontalLine, dicVerticalLineIf WRITE_LOG = 1 Then"Remove Vertical..."End IfRemoveShortLines dicVerticalLine, dicHorizontalLinedicHorizontalLinedicVerticalLine, False'DrawTextsExportExcelIf WRITE_LOG = 1 Thenfile.CloseEnd IfEnd If'??????????"ttps asEach tps In dicHorizontalLine'NextEnd SubSub ExportExcel()Dim xlApp As Excel.ApplicationDim xlBook As Excel.WorkbookDim xlSheet As Excel.WorkSheetSet xlApp = CreateObject("Excel.Application")Set xlBook = xlApp.workbooks.AddSet xlsheet = xlBook.Worksheets(1)''dicVerticalLineDim dicHorizontalSortDim dicVerticalSortSet dicHorizontalSort = CreateObject("Scripting.Dictionary")Set dicVerticalSort = CreateObject("Scripting.Dictionary")SortDic dicHorizontalLine, dicHorizontalSortSortDic dicVerticalLine, dicVerticalSortDim dicCellsSet dicCells = CreateObject("Scripting.Dictionary")iHorizontal = dicHorizontalSort.CountiVertical = dicVerticalSort.CountDim downH, upHDim downV, upVDim x, yDim col_from, col_to, row_from, row_toDim strCell As StringDim aCell As CCellDim txt As CTextFor Each atxt In arrTextSet txt = atxtcol) = txt= col + 1x = txt.GetMidX()y = txt.GetMidY()GetScale dicHorizontalLine, y, x, downH, upHGetScale dicVerticalLine, x, y, downV, upVx, y, dicHorizontalSort(downH), dicHorizontalSort(upH), dicVerticalSort(downV), dicVerticalSort(upV)txt.TextString, downV, x, upV, downH, y, upHtxt.TextString, dicVerticalSort(downV), x, dicVerticalSort(upV), iHorizontal - dicHorizontalSort(downH), y, iHorizontal - dicHorizontalSort(upH)col_from = dicVerticalSort(downV) - 1col_to = dicVerticalSort(upV) - 1row_from = iHorizontal - dicHorizontalSort(upH)row_to = iHorizontal - dicHorizontalSort(downH)strCell = xlsheet.Cells(row_from + 1, col_from + 1)+ 1, col_from + 1), xlsheet.Cells(row_to, col_to)).MergeCells = True+ 1, col_from + 1).NumberFormat = "@"strCell = (col_from + 1) & "-" & (row_from + 1)If dicCells.exists(strCell) ThentxtElseSet aCell = New CCell= col_from + 1= row_from + 1txtstrCell, aCellEnd IfNextFor Each ecell In dicCellsSet aCell = dicCells(ecell)aCell.col) = aCell.GetStringNextIf Trim(strCell) <> "" ThenstrCell = strCell & Chr(10) & txt.TextStringElsestrCell = txt.TextStringEnd If+ 1, col_from + 1) = txt.TextString'//调整导出数据格式max_col = CNtoW(xlsheet.usedrange.Columns.Count, xlsheet)max_row = xlsheet.usedrange.Rows.Count:" & max_col).EntireColumn.AutoFitSet rng = xlsheet.range("a1:" & max_col & max_row)rngrng= TrueEnd SubSub GetScale(dic, y_x, x_y, down, up)down = -1up = 9999999For Each v In dicIf dic(v).IsWithin(x_y) ThenIf v > down And v < y_x Thendown = vEnd IfIf v < up And v > y_x Thenup = vEnd IfEnd IfNextEnd SubSub SortDic(dic, sort)= 0For Each num In dici = 1For Each num1 In dicIf num > num1 Theni = i + 1End IfNext= j + 1num, iNextEach num In sortDebug.Print num, dicHorizontalSort(num)'NextEnd SubSub SaveLines(dic, fn)If WRITE_LOG = 1 ThenDim fsObjSet fsObj = CreateObject("Scripting.FileSystemObject")Set file = fsObj.CreateTextFile(ThisDrawing.Path & "\" & fn & ".csv", True)fn & ";Min;Max"For Each tp In dicFor Each ctp In dic(tp).GetPointstp & ";" & ctp.MinP & ";" & ctp.MaxPNextNextfile.CloseEnd IfEnd SubSub DrawLines(dic, Optional Horizontal As Boolean = True)Dim ctp As CPointFor Each tps In dicFor Each tp In dic(tps).GetPointsSet ctp = tpDrawLine tps, ctp.MinP, ctp.MaxP, HorizontalNextNextEnd SubSub DrawTexts()Dim MyText As AcadTextFor Each txt In arrTextMyText = ThisDrawing.ModelSpace.AddText(txt.TextString, txt.MinPoint, 1)NextEnd SubSub DrawLine(pc, p1, p2, Optional Horizontal As Boolean = True)Dim sp(0 To 2) As DoubleDim ep(0 To 2) As Doublex_offset = 0y_offset = 25If Horizontal Then= p1 + x_offset= pc + y_offset= 0= p2 + x_offset= pc + y_offset= 0Else= pc + x_offset= p1 + y_offset= 0= pc + x_offset= p2 + y_offset= 0End IfDim MyLine As AcadLineSet MyLine = ThisDrawing.ModelSpace.AddLine(sp, ep)End SubSub RemoveShortLines(ori, ref)Dim ctp As CPointDim dicRemove As VariantFor Each tps In oriSet dicRemove = CreateObject("Scripting.Dictionary")= 1For Each tp In ori(tps).GetPointsSet ctp = tp"Remove?", tps, tp.MinP, tp.MaxP=If WRITE_LOG = 1 Then"Remove?" & ";" & tps & ";" & tp.MinP & ";" & tp.MaxPEnd IfIf Not IsBorder(ctp, ref) Thenctp, ""End IfNext(dicRemove)Set dicRemove = NothingNextFor Each tps In oriIf ori(tps).Count = 0 ThentpsEnd IfNextEnd SubFunction IsBorder(ByVal tp As CPoint, ByVal ref) As BooleanIsBorder = FalseFor Each tps In refIf tps = tp.MinP Or _tps = tp.MaxP ThenIsBorder = TrueExit FunctionEnd IfNextEnd FunctionSub AddLine(StartPoint, EndPoint)NumDigits = 1ShortestLine = 0.3line_len = ((StartPoint(0) - EndPoint(0)) ^ 2 + (StartPoint(1) - EndPoint(1)) ^ 2) ^ 0.5If line_len < ShortestLine Then Exit Sub= Round(StartPoint(0), NumDigits)= Round(StartPoint(1), NumDigits)= Round(EndPoint(0), NumDigits)= Round(EndPoint(1), NumDigits)If StartPoint(0) = EndPoint(0) ThenAddLineTo dicVerticalLine, StartPoint(0), StartPoint(1), EndPoint(1)End IfIf StartPoint(1) = EndPoint(1) ThenAddLineTo dicHorizontalLine, StartPoint(1), StartPoint(0), EndPoint(0)End IfEnd SubSub AddLineTo(dicLine, x_y, sp, ep)If dicLine.exists(x_y) Thensp, epElseDim tps As CPointSetSet tps = New CPointSetsp, epx_y, tpsEnd IfEnd Sub'/////////////////////////////////////////////////////////////////////调整格式'/////////////////////////////////////////////////////////////////////'列数转字母Function CNtoW(ByVal num As Long, sht) As StringCNtoW = Replace(sht.Cells(1, num).Address(False, False), "1", "")End FunctionSub 调整边框(rng)With rng.Borders(7)= 1= 0= 0= 2End WithWith rng.Borders(8)= 1= 0= 0= 2End WithWith rng.Borders(9)= 1= 0= 0= 2End WithWith rng.Borders(10)= 1= 0= 0= 2End WithWith rng.Borders(11)= 1= 0= 0= 2End WithWith rng.Borders(12)= 1= 0= 0= 2End WithEnd SubSub 居中对齐(rng)With rng= -4108= -4108= True= 0= False= 0= False= -5002End WithEnd Sub
类模块相关代码:
模块名:CCell
Private TextList() As CTextPublic col As IntegerPublic row As IntegerPublic Sub AddText(txt As CText)Count = 0If 1 ThenOn Error Resume NextCount = UBound(TextList)End IfCount = Count + 1ReDim Preserve TextList(1 To Count)Set TextList(Count) = txtEnd SubPublic Function GetString()On Error Resume NextCount = UBound(TextList)If Count = 1 ThenGetString = TextList(1).TextStringExit FunctionEnd IfGetString = ""Dim strList() As String, strTemp As StringDim yList() As Double, yTemp As DoubleReDim strList(1 To Count)ReDim yList(1 To Count)For i = 1 To Count'For Each txt In TextList'GetString = GetString & Chr(10) & txt.TextStringstrList(i) = TextList(i).TextStringyList(i) = TextList(i).GetMidYNextFor i = 1 To Count - 1For j = i + 1 To CountIf yList(i) < yList(j) ThenyTemp = yList(i)yList(i) = yList(j)yList(j) = yTempstrTemp = strList(i)strList(i) = strList(j)strList(j) = strTempEnd IfNextNextGetString = strList(1)For i = 2 To CountGetString = GetString & Chr(10) & strList(i)NextEnd Function
模块名:CPoint
Public MinP As DoublePublic MaxP As Double
模块名:CPointSet
Public Count As IntegerPrivate arrPoints() As CPointPublic Function GetPoints()GetPoints = arrPointsEnd FunctionPublic Function IsWithin(v) As BooleanIsWithin = FalseFor Each p In arrPointsIf p.MinP <= v And p.MaxP >= v ThenIsWithin = TrueExit FunctionEnd IfNextEnd FunctionPublic Function RemoveShortLines(dicRemove) As IntegerRemoveShortLines = CountIf Count < 1 Then Exit FunctionDim arrP() As CPointReDim arrP(1 To Count)j = 0Dim bRemove As BooleanFor i = 1 To CountbRemove = FalseFor Each p In dicRemoveIf p.MinP = arrPoints(i).MinP And p.MaxP = arrPoints(i).MaxP ThenbRemove = TrueEnd IfNextIf Not bRemove Thenj = j + 1Set arrP(j) = arrPoints(i)End IfNextIf j > 0 ThenReDim Preserve arrP(1 To j)arrPoints = arrPEnd IfCount = jRemoveShortLines = CountEnd FunctionPublic Function RemoveWith(ByVal cpt As CPoint) As IntegerIf Count = 0 ThenCount = 0RemoveWith = 0Exit FunctionEnd IfiRemoveAt = 0For i = 1 To CountIf arrPoints(i).MaxP = cpt.MaxP And arrPoints(i).MinP = cpt.MinP TheniRemoveAt = iExit ForEnd IfNextIf iRemoveAt > 0 ThenCount = Count - 1If Count > 0 Then'If iRemoveAt <= Count ThenFor j = iRemoveAt To CountarrPoints(j).MaxP = arrPoints(j + 1).MaxParrPoints(j).MinP = arrPoints(j + 1).MinPNext'End IfReDim Preserve arrPoints(1 To Count)ElseCount = 0'ReDim arrPoints()End IfEnd IfRemoveWith = CountEnd FunctionPublic Sub Add(Point1, Point2)If Point1 > Point2 ThenMinP = Point2MaxP = Point1ElseMinP = Point1MaxP = Point2End IfIf Count > 0 ThenFor Each point In arrPointsIf point.MaxP = MinP Thenpoint.MaxP = MaxPExit SubEnd IfIf point.MinP = MaxP Thenpoint.MinP = MinPExit SubEnd IfIf point.MaxP = MaxP And point.MinP = MinP Then Exit SubNextEnd IfCount = Count + 1ReDim Preserve arrPoints(1 To Count)Set arrPoints(Count) = New CPointarrPoints(Count).MinP = MinParrPoints(Count).MaxP = MaxPEnd Sub
模块名:CText
Private MinPoint(0 To 2) As DoublePrivate MaxPoint(0 To 2) As DoublePublic TextString As StringPublic Sub SetMinPoint(p)MinPoint(0) = p(0)MinPoint(1) = p(1)MinPoint(2) = p(2)End SubPublic Sub SetMaxPoint(p)MaxPoint(0) = p(0)MaxPoint(1) = p(1)MaxPoint(2) = p(2)End SubPublic Function GetMinPoint()GetMinPoint = MinPointEnd FunctionPublic Function GetMaxPoint()GetMaxPoint = MaxPoint()End FunctionPublic Function GetMidX()GetMidX = (MinPoint(0) + MaxPoint(0)) / 2End FunctionPublic Function GetMidY()GetMidY = (MinPoint(1) + MaxPoint(1)) / 2End Function
【建议收藏】VBA说历史文章汇总 速码工具箱2.0发布,更强大的功能等你来体验! VBA会被Python代替吗? 代码存储美化工具测评-【VBE2019】 Excel和Word数据交互读取(生成合同) 
评论
