VBA实现Excel与CAD表格互转
▎案例需求
最近换了工作,专职给单位做VBA开发的。很幸运,领导很重视利用VBA来提高效率,实现一些办公流程的自动化。其中有一项内容就是利用Excel数据批量绘制CAD图纸。
关于CAD VBA的东西,会更新几篇,也是作为自己的备忘。本篇文章更新Excel与CAD表格互相导出导入。
▎具体效果(Excel表格导入CAD)
支持合并单元格,如需更细致的需求,需要修改代码相应部分。
▎详细源代码(Excel表格导入CAD)
窗体源代码都在这里,源文件我就不放了。VB画个窗体还是轻轻松松的。
Option Explicit
Private Sub cmdCancel_Click()
Unload Me
End Sub
Private Sub cmdOK_Click()
On Error Resume Next
'获取插入点坐标
Dim ptInsert(2) As Double
ptInsert(0) = txtX.Text: ptInsert(1) = txtY.Text: ptInsert(2) = 0
'获取并连接当前但开的excel程序及当前表
Dim excelApp As Object
Dim excelSheet As Object
Set excelApp = GetObject(, "excel.application")
If Err <> 0 Then
MsgBox "Excel程序未运行,请打开Excel程序!"
Err.Clear
Exit Sub
End If
Set excelSheet = excelApp.activesheet
'保存要转化的区域
Dim ranges As Object
If optAll.Value = True Then
Set ranges = excelSheet.usedrange
ElseIf optSelect = True Then
Set ranges = excelApp.Selection
End If
'对每个单元进行操作
Dim excelRg As Object
For Each excelRg In ranges
addTableAndText ranges, excelRg, ptInsert
Next excelRg
'释放Excel对象
Set excelSheet = Nothing
Set excelApp = Nothing
End 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 Double
Dim ptLB(2) As Double
Dim ptRT(2) As Double
Dim ptRB(2) As Double
'声明一个单元格对象来求顶点坐标
Dim rg11 As Object
Set rg11 = excelRg.Offset(1, 1)
'获取四个顶点的坐标
ptLT(0) = ptInsert(0) + excelRg.Left * 0.8 - ranges.Left * 0.8
ptLT(1) = ptInsert(1) - (excelRg.top - ranges.top)
ptLT(2) = 0
ptRB(0) = ptInsert(0) + rg11.Left * 0.8 - ranges.Left * 0.8
ptRB(1) = ptInsert(1) - (rg11.top - ranges.top)
ptRB(2) = 0
ptLB(0) = ptLT(0)
ptLB(1) = ptRB(1)
ptLB(2) = 0
ptRT(0) = ptRB(0)
ptRT(1) = ptLT(1)
ptRT(2) = 0
'左侧线
If excelRg.Column = ranges.Column And excelRg.borders.Item(1).linestyle > 0 Then
Set objLine = ThisDrawing.ModelSpace.AddLine(ptLT, ptLB)
setTableColor objLine, excelRg.borders.Item(1).color
End If
'右侧线
If excelRg.borders.Item(2).linestyle > 0 Then
Set objLine = ThisDrawing.ModelSpace.AddLine(ptRT, ptRB)
setTableColor objLine, excelRg.borders.Item(2).color
End If
'上边线
If excelRg.row = ranges.row And excelRg.borders.Item(3).linestyle > 0 Then
Set objLine = ThisDrawing.ModelSpace.AddLine(ptLT, ptRT)
setTableColor objLine, excelRg.borders.Item(3).color
End If
'下边线
If excelRg.borders.Item(4).linestyle > 0 Then
Set objLine = ThisDrawing.ModelSpace.AddLine(ptLB, ptRB)
setTableColor objLine, excelRg.borders.Item(4).color
End If
'添加文字
Dim objText As AcadText
Set objText = ThisDrawing.ModelSpace.AddText(excelRg.Text, ptLB, excelRg.Font.Size * 0.9)
'设置文字的颜色
setTextColor objText, excelRg.Font.color
'设置文字的对其方式
setTextAlignMent objText, ptLT, ptRB
End Function
'改变表格的颜色
Public Function setTableColor(ByVal objEntity As AcadEntity, ByVal color As Long)
If optTableColor2.Value = True Then
If cmbTableColor.Text = "By Layer" Then
Exit Function
ElseIf cmbTableColor.Text = "红色" Then
objEntity.color = acRed
ElseIf cmbTableColor.Text = "绿色" Then
objEntity.color = acGreen
ElseIf cmbTableColor.Text = "蓝色" Then
objEntity.color = acBlue
End If
Exit Function
End If
Dim colorR As Long
Dim colorG As Long
Dim colorB As Long
If optTableColor1.Value = True Then
If color <> 0 Then
Dim entityColor As AcadAcCmColor
Set entityColor = AcadApplication.GetInterfaceObject("AutoCAD.AcCmColor.19")
colorR = color And 255
colorG = (color And 65280) / 256
colorB = (color And 16711680) / 65536
entityColor.SetRGB colorR, colorG, colorB
objEntity.TrueColor = entityColor
End If
End If
End Function
'改变文字的颜色
Public Function setTextColor(ByVal objEntity As AcadEntity, ByVal color As Long)
If optTextColor2.Value = True Then
If cmbTextColor.Text = "By Layer" Then
Exit Function
ElseIf cmbTextColor.Text = "红色" Then
objEntity.color = acRed
ElseIf cmbTextColor.Text = "绿色" Then
objEntity.color = acGreen
ElseIf cmbTextColor.Text = "蓝色" Then
objEntity.color = acBlue
End If
Exit Function
End If
Dim colorR As Long
Dim colorG As Long
Dim colorB As Long
If optTextColor1.Value = True Then
If color <> 0 Then
Dim entityColor As AcadAcCmColor
Set entityColor = AcadApplication.GetInterfaceObject("AutoCAD.AcCmColor.19")
colorR = color And 255
colorG = (color And 65280) / 256
colorB = (color And 16711680) / 65536
entityColor.SetRGB colorR, colorG, colorB
objEntity.TrueColor = entityColor
End If
End If
End Function
'文字的对齐
Public Function setTextAlignMent(ByVal objText As AcadText, ByVal ptLT As Variant, ByVal ptRB As Variant)
Dim ptMC(2) As Double
ptMC(0) = (ptLT(0) + ptRB(0)) / 2
ptMC(1) = (ptLT(1) + ptRB(1)) / 2
ptMC(2) = 0
If optTextAlignment1.Value = True Then
objText.Alignment = acAlignmentMiddleCenter
objText.Move objText.TextAlignmentPoint, ptMC
Exit Function
End If
Dim ptML(2) As Double
ptML(0) = ptLT(0)
ptML(1) = (ptLT(1) + ptRB(1)) / 2
ptML(2) = 0
If optTextAlignment2.Value = True Then
objText.Alignment = acAlignmentMiddleLeft
objText.Move objText.TextAlignmentPoint, ptML
Exit Function
End If
Dim ptMR(2) As Double
ptMR(0) = ptRB(0)
ptMR(1) = (ptLT(1) + ptRB(1)) / 2
ptMR(2) = 0
If optTextAlignment3.Value = True Then
objText.Alignment = acAlignmentMiddleRight
objText.Move objText.TextAlignmentPoint, ptMR
End If
End Function
Private Sub cmdPickPoint_Click()
On Error Resume Next
Dim pt As Variant
UserForm1.Hide
pt = ThisDrawing.Utility.GetPoint(, "请选择插入点:")
txtX.Text = pt(0): txtY.Text = pt(1)
UserForm1.show
End 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 Function
Private Sub optTableColor1_Change()
If optTableColor1.Value = True Then
cmbTableColor.Enabled = False
cmbTableColor.Text = ""
End If
End Sub
Private Sub optTableColor2_Click()
If optTableColor2.Value = True Then
cmbTableColor.Enabled = True
cmbTableColor.Text = "By Layer"
End If
End Sub
Private Sub optTextColor1_Change()
If optTextColor1.Value = True Then
cmbTextColor.Enabled = False
cmbTextColor.Text = ""
End If
End Sub
Private Sub optTextColor2_Change()
If optTextColor2.Value = True Then
cmbTextColor.Enabled = True
cmbTextColor.Text = "By Layer"
End If
End Sub
Private Sub UserForm_Initialize()
txtX.Text = 0: txtY.Text = 0
optAll.Value = True
optTableColor1.Value = True
optTextColor1.Value = True
addCombbox
optTextAlignment1.Value = True
End Sub
▎具体效果(CAD表格导入Excel)
支持合并单元格,如需更细致的需求,需要修改代码相应部分。
▎详细源代码(CAD表格导入Excel)
由于涉及到类代码,这里放个代码截图。
Dim dicHorizontalLine As Variant
Dim dicVerticalLine As Variant
Dim arrText() As CText
Dim file
Const WRITE_LOG = 0
Dim WorkDrawing
Sub ReadTable()
"Type;Object;TagID;Position;Track;Segment;Accuracy;Note;SetupOffset"
SelectionName = "ss1"
Dim sset As AcadSelectionSet
Dim element As AcadEntity
For Each sset In ThisDrawing.SelectionSets
If sset.Name = SelectionName Then
sset.Delete
Exit For
End If
Next
Erase arrText
Set dicHorizontalLine = CreateObject("Scripting.Dictionary")
Set dicVerticalLine = CreateObject("Scripting.Dictionary")
dicText = CreateObject("Scripting.Dictionary")
Dim txt As AcadText
Dim txtNum As Integer
txtNum = 0
Set sset = ThisDrawing.SelectionSets.Add(SelectionName)
Dim objType As String
sset.SelectOnScreen
If sset.Count > 0 Then
For Each element In sset
objType = element.ObjectName
Select Case objType
Case "AcDbLine"
AddLine element.StartPoint, element.EndPoint
Case "AcDbText"
Set txt = element
If 1 Then
On Error Resume Next
txtNum = UBound(arrText)
End If
txtNum = txtNum + 1
ReDim Preserve arrText(1 To txtNum)
Set arrText(txtNum) = New CText
txt.TextString =
Dim MinPoint, MaxPoint
MinPoint, MaxPoint
MaxPoint
MinPoint
'GetBoundingBox
End Select
Next
If WRITE_LOG = 1 Then
SaveLines dicHorizontalLine, "Horizontal"
SaveLines dicVerticalLine, "Vertical"
Dim fsObj
Set fsObj = CreateObject("Scripting.FileSystemObject")
Set file = fsObj.CreateTextFile(ThisDrawing.Path & "\debug.csv", True)
"Remove Horizontal..."
End If
RemoveShortLines dicHorizontalLine, dicVerticalLine
If WRITE_LOG = 1 Then
"Remove Vertical..."
End If
RemoveShortLines dicVerticalLine, dicHorizontalLine
dicHorizontalLine
dicVerticalLine, False
'DrawTexts
ExportExcel
If WRITE_LOG = 1 Then
file.Close
End If
End If
'??????????"
ttps as
Each tps In dicHorizontalLine
'Next
End Sub
Sub ExportExcel()
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.WorkSheet
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.workbooks.Add
Set xlsheet = xlBook.Worksheets(1)
'
'dicVerticalLine
Dim dicHorizontalSort
Dim dicVerticalSort
Set dicHorizontalSort = CreateObject("Scripting.Dictionary")
Set dicVerticalSort = CreateObject("Scripting.Dictionary")
SortDic dicHorizontalLine, dicHorizontalSort
SortDic dicVerticalLine, dicVerticalSort
Dim dicCells
Set dicCells = CreateObject("Scripting.Dictionary")
iHorizontal = dicHorizontalSort.Count
iVertical = dicVerticalSort.Count
Dim downH, upH
Dim downV, upV
Dim x, y
Dim col_from, col_to, row_from, row_to
Dim strCell As String
Dim aCell As CCell
Dim txt As CText
For Each atxt In arrText
Set txt = atxt
col) = txt
col + 1 =
x = txt.GetMidX()
y = txt.GetMidY()
GetScale dicHorizontalLine, y, x, downH, upH
GetScale dicVerticalLine, x, y, downV, upV
x, y, dicHorizontalSort(downH), dicHorizontalSort(upH), dicVerticalSort(downV), dicVerticalSort(upV)
txt.TextString, downV, x, upV, downH, y, upH
txt.TextString, dicVerticalSort(downV), x, dicVerticalSort(upV), iHorizontal - dicHorizontalSort(downH), y, iHorizontal - dicHorizontalSort(upH)
col_from = dicVerticalSort(downV) - 1
col_to = dicVerticalSort(upV) - 1
row_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) Then
txt
Else
Set aCell = New CCell
col_from + 1 =
row_from + 1 =
txt
strCell, aCell
End If
Next
For Each ecell In dicCells
Set aCell = dicCells(ecell)
aCell.col) = aCell.GetString
Next
If Trim(strCell) <> "" Then
strCell = strCell & Chr(10) & txt.TextString
Else
strCell = txt.TextString
End If
+ 1, col_from + 1) = txt.TextString
'//调整导出数据格式
max_col = CNtoW(xlsheet.usedrange.Columns.Count, xlsheet)
max_row = xlsheet.usedrange.Rows.Count
" & max_col).EntireColumn.AutoFit :
Set rng = xlsheet.range("a1:" & max_col & max_row)
rng
rng
True =
End Sub
Sub GetScale(dic, y_x, x_y, down, up)
down = -1
up = 9999999
For Each v In dic
If dic(v).IsWithin(x_y) Then
If v > down And v < y_x Then
down = v
End If
If v < up And v > y_x Then
up = v
End If
End If
Next
End Sub
Sub SortDic(dic, sort)
0 =
For Each num In dic
i = 1
For Each num1 In dic
If num > num1 Then
i = i + 1
End If
Next
j + 1 =
num, i
Next
Each num In sort
Debug.Print num, dicHorizontalSort(num)
'Next
End Sub
Sub SaveLines(dic, fn)
If WRITE_LOG = 1 Then
Dim fsObj
Set fsObj = CreateObject("Scripting.FileSystemObject")
Set file = fsObj.CreateTextFile(ThisDrawing.Path & "\" & fn & ".csv", True)
fn & ";Min;Max"
For Each tp In dic
For Each ctp In dic(tp).GetPoints
tp & ";" & ctp.MinP & ";" & ctp.MaxP
Next
Next
file.Close
End If
End Sub
Sub DrawLines(dic, Optional Horizontal As Boolean = True)
Dim ctp As CPoint
For Each tps In dic
For Each tp In dic(tps).GetPoints
Set ctp = tp
DrawLine tps, ctp.MinP, ctp.MaxP, Horizontal
Next
Next
End Sub
Sub DrawTexts()
Dim MyText As AcadText
For Each txt In arrText
MyText = ThisDrawing.ModelSpace.AddText(txt.TextString, txt.MinPoint, 1)
Next
End Sub
Sub DrawLine(pc, p1, p2, Optional Horizontal As Boolean = True)
Dim sp(0 To 2) As Double
Dim ep(0 To 2) As Double
x_offset = 0
y_offset = 25
If Horizontal Then
p1 + x_offset =
pc + y_offset =
0 =
p2 + x_offset =
pc + y_offset =
0 =
Else
pc + x_offset =
p1 + y_offset =
0 =
pc + x_offset =
p2 + y_offset =
0 =
End If
Dim MyLine As AcadLine
Set MyLine = ThisDrawing.ModelSpace.AddLine(sp, ep)
End Sub
Sub RemoveShortLines(ori, ref)
Dim ctp As CPoint
Dim dicRemove As Variant
For Each tps In ori
Set dicRemove = CreateObject("Scripting.Dictionary")
1 =
For Each tp In ori(tps).GetPoints
Set ctp = tp
"Remove?", tps, tp.MinP, tp.MaxP
=
If WRITE_LOG = 1 Then
"Remove?" & ";" & tps & ";" & tp.MinP & ";" & tp.MaxP
End If
If Not IsBorder(ctp, ref) Then
ctp, ""
End If
Next
(dicRemove)
Set dicRemove = Nothing
Next
For Each tps In ori
If ori(tps).Count = 0 Then
tps
End If
Next
End Sub
Function IsBorder(ByVal tp As CPoint, ByVal ref) As Boolean
IsBorder = False
For Each tps In ref
If tps = tp.MinP Or _
tps = tp.MaxP Then
IsBorder = True
Exit Function
End If
Next
End Function
Sub AddLine(StartPoint, EndPoint)
NumDigits = 1
ShortestLine = 0.3
line_len = ((StartPoint(0) - EndPoint(0)) ^ 2 + (StartPoint(1) - EndPoint(1)) ^ 2) ^ 0.5
If 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) Then
AddLineTo dicVerticalLine, StartPoint(0), StartPoint(1), EndPoint(1)
End If
If StartPoint(1) = EndPoint(1) Then
AddLineTo dicHorizontalLine, StartPoint(1), StartPoint(0), EndPoint(0)
End If
End Sub
Sub AddLineTo(dicLine, x_y, sp, ep)
If dicLine.exists(x_y) Then
sp, ep
Else
Dim tps As CPointSet
Set tps = New CPointSet
sp, ep
x_y, tps
End If
End Sub
'/////////////////////////////////////////////////////////////////////
调整格式
'/////////////////////////////////////////////////////////////////////
'列数转字母
Function CNtoW(ByVal num As Long, sht) As String
CNtoW = Replace(sht.Cells(1, num).Address(False, False), "1", "")
End Function
Sub 调整边框(rng)
With rng.Borders(7)
1 =
0 =
0 =
2 =
End With
With rng.Borders(8)
1 =
0 =
0 =
2 =
End With
With rng.Borders(9)
1 =
0 =
0 =
2 =
End With
With rng.Borders(10)
1 =
0 =
0 =
2 =
End With
With rng.Borders(11)
1 =
0 =
0 =
2 =
End With
With rng.Borders(12)
1 =
0 =
0 =
2 =
End With
End Sub
Sub 居中对齐(rng)
With rng
-4108 =
-4108 =
True =
0 =
False =
0 =
False =
-5002 =
End With
End Sub
类模块相关代码:
模块名:CCell
Private TextList() As CText
Public col As Integer
Public row As Integer
Public Sub AddText(txt As CText)
Count = 0
If 1 Then
On Error Resume Next
Count = UBound(TextList)
End If
Count = Count + 1
ReDim Preserve TextList(1 To Count)
Set TextList(Count) = txt
End Sub
Public Function GetString()
On Error Resume Next
Count = UBound(TextList)
If Count = 1 Then
GetString = TextList(1).TextString
Exit Function
End If
GetString = ""
Dim strList() As String, strTemp As String
Dim yList() As Double, yTemp As Double
ReDim strList(1 To Count)
ReDim yList(1 To Count)
For i = 1 To Count
'For Each txt In TextList
'GetString = GetString & Chr(10) & txt.TextString
strList(i) = TextList(i).TextString
yList(i) = TextList(i).GetMidY
Next
For i = 1 To Count - 1
For j = i + 1 To Count
If yList(i) < yList(j) Then
yTemp = yList(i)
yList(i) = yList(j)
yList(j) = yTemp
strTemp = strList(i)
strList(i) = strList(j)
strList(j) = strTemp
End If
Next
Next
GetString = strList(1)
For i = 2 To Count
GetString = GetString & Chr(10) & strList(i)
Next
End Function
模块名:CPoint
Public MinP As Double
Public MaxP As Double
模块名:CPointSet
Public Count As Integer
Private arrPoints() As CPoint
Public Function GetPoints()
GetPoints = arrPoints
End Function
Public Function IsWithin(v) As Boolean
IsWithin = False
For Each p In arrPoints
If p.MinP <= v And p.MaxP >= v Then
IsWithin = True
Exit Function
End If
Next
End Function
Public Function RemoveShortLines(dicRemove) As Integer
RemoveShortLines = Count
If Count < 1 Then Exit Function
Dim arrP() As CPoint
ReDim arrP(1 To Count)
j = 0
Dim bRemove As Boolean
For i = 1 To Count
bRemove = False
For Each p In dicRemove
If p.MinP = arrPoints(i).MinP And p.MaxP = arrPoints(i).MaxP Then
bRemove = True
End If
Next
If Not bRemove Then
j = j + 1
Set arrP(j) = arrPoints(i)
End If
Next
If j > 0 Then
ReDim Preserve arrP(1 To j)
arrPoints = arrP
End If
Count = j
RemoveShortLines = Count
End Function
Public Function RemoveWith(ByVal cpt As CPoint) As Integer
If Count = 0 Then
Count = 0
RemoveWith = 0
Exit Function
End If
iRemoveAt = 0
For i = 1 To Count
If arrPoints(i).MaxP = cpt.MaxP And arrPoints(i).MinP = cpt.MinP Then
iRemoveAt = i
Exit For
End If
Next
If iRemoveAt > 0 Then
Count = Count - 1
If Count > 0 Then
'If iRemoveAt <= Count Then
For j = iRemoveAt To Count
arrPoints(j).MaxP = arrPoints(j + 1).MaxP
arrPoints(j).MinP = arrPoints(j + 1).MinP
Next
'End If
ReDim Preserve arrPoints(1 To Count)
Else
Count = 0
'ReDim arrPoints()
End If
End If
RemoveWith = Count
End Function
Public Sub Add(Point1, Point2)
If Point1 > Point2 Then
MinP = Point2
MaxP = Point1
Else
MinP = Point1
MaxP = Point2
End If
If Count > 0 Then
For Each point In arrPoints
If point.MaxP = MinP Then
point.MaxP = MaxP
Exit Sub
End If
If point.MinP = MaxP Then
point.MinP = MinP
Exit Sub
End If
If point.MaxP = MaxP And point.MinP = MinP Then Exit Sub
Next
End If
Count = Count + 1
ReDim Preserve arrPoints(1 To Count)
Set arrPoints(Count) = New CPoint
arrPoints(Count).MinP = MinP
arrPoints(Count).MaxP = MaxP
End Sub
模块名:CText
Private MinPoint(0 To 2) As Double
Private MaxPoint(0 To 2) As Double
Public TextString As String
Public Sub SetMinPoint(p)
MinPoint(0) = p(0)
MinPoint(1) = p(1)
MinPoint(2) = p(2)
End Sub
Public Sub SetMaxPoint(p)
MaxPoint(0) = p(0)
MaxPoint(1) = p(1)
MaxPoint(2) = p(2)
End Sub
Public Function GetMinPoint()
GetMinPoint = MinPoint
End Function
Public Function GetMaxPoint()
GetMaxPoint = MaxPoint()
End Function
Public Function GetMidX()
GetMidX = (MinPoint(0) + MaxPoint(0)) / 2
End Function
Public Function GetMidY()
GetMidY = (MinPoint(1) + MaxPoint(1)) / 2
End Function
【建议收藏】VBA说历史文章汇总 速码工具箱2.0发布,更强大的功能等你来体验! VBA会被Python代替吗? 代码存储美化工具测评-【VBE2019】 Excel和Word数据交互读取(生成合同)
评论