1
1

Tools.bas 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186
  1. '// This is free and unencumbered software released into the public domain.
  2. '// For more information, please refer to https://github.com/hongwenjun
  3. '// 简易火车排列
  4. Public Function Simple_Train_Arrangement(Space_Width As Double)
  5. API.BeginOpt
  6. Dim ssr As ShapeRange, s As Shape
  7. Dim cnt As Integer
  8. Set ssr = ActiveSelectionRange
  9. cnt = 1
  10. #If VBA7 Then
  11. ' ssr.sort " @shape1.top>@shape2.top"
  12. ssr.Sort " @shape1.left<@shape2.left"
  13. #Else
  14. ' X4 不支持 ShapeRange.sort
  15. #End If
  16. ActiveDocument.ReferencePoint = cdrTopLeft
  17. For Each s In ssr
  18. '// 底对齐 If cnt > 1 Then s.SetPosition ssr(cnt - 1).RightX, ssr(cnt - 1).BottomY
  19. '// 改成顶对齐 2022-08-10
  20. ActiveDocument.ReferencePoint = cdrTopLeft + cdrBottomTop
  21. If cnt > 1 Then s.SetPosition ssr(cnt - 1).RightX + Space_Width, ssr(cnt - 1).TopY
  22. cnt = cnt + 1
  23. Next s
  24. API.EndOpt
  25. End Function
  26. '// 简易阶梯排列
  27. Public Function Simple_Ladder_Arrangement(Space_Width As Double)
  28. API.BeginOpt
  29. Dim ssr As ShapeRange, s As Shape
  30. Dim cnt As Integer
  31. Set ssr = ActiveSelectionRange
  32. cnt = 1
  33. #If VBA7 Then
  34. ssr.Sort " @shape1.top>@shape2.top"
  35. ' ssr.sort " @shape1.left<@shape2.left"
  36. #Else
  37. ' X4 不支持 ShapeRange.sort
  38. #End If
  39. ActiveDocument.ReferencePoint = cdrTopLeft
  40. For Each s In ssr
  41. If cnt > 1 Then s.SetPosition ssr(cnt - 1).LeftX, ssr(cnt - 1).BottomY - Space_Width
  42. cnt = cnt + 1
  43. Next s
  44. API.EndOpt
  45. End Function
  46. '// 文本转曲线 默认使用简单转曲,参数 all=1 ,支持框选和图框剪裁内的文本
  47. Public Function TextShape_ConvertToCurves(Optional all = 0)
  48. API.BeginOpt
  49. On Error GoTo ErrorHandler
  50. Dim s As Shape, cnt As Long
  51. If all = 1 Then
  52. For Each s In API.FindAllShapes.Shapes.FindShapes(, cdrTextShape)
  53. s.ConvertToCurves
  54. cnt = cnt + 1
  55. Next s
  56. Else
  57. For Each s In ActivePage.FindShapes(, cdrTextShape)
  58. s.ConvertToCurves
  59. cnt = cnt + 1
  60. Next s
  61. End If
  62. ErrorHandler:
  63. API.EndOpt
  64. End Function
  65. '// 复制物件
  66. Public Function copy_shape()
  67. Dim OrigSelection As ShapeRange
  68. Set OrigSelection = ActiveSelectionRange
  69. OrigSelection.Copy
  70. End Function
  71. '// 旋转物件角度
  72. Public Function Rotate_Shapes(n As Double)
  73. API.BeginOpt
  74. Dim sh As Shape, shs As Shapes
  75. Set shs = ActiveSelection.Shapes
  76. Dim s As String, size As String
  77. For Each sh In shs
  78. sh.Rotate n
  79. Next sh
  80. API.EndOpt
  81. End Function
  82. '// 得到物件尺寸
  83. Public Function get_shape_size(ByRef sx As Double, ByRef sy As Double)
  84. ActiveDocument.Unit = cdrMillimeter
  85. Dim sh As ShapeRange
  86. Set sh = ActiveSelectionRange
  87. sx = sh.SizeWidth
  88. sy = sh.SizeHeight
  89. sx = Int(sx * 100 + 0.5) / 100
  90. sy = Int(sy * 100 + 0.5) / 100
  91. End Function
  92. '// 批量设置物件尺寸
  93. Public Function Set_Shapes_size(ByRef sx As Double, ByRef sy As Double)
  94. API.BeginOpt
  95. ActiveDocument.ReferencePoint = cdrCenter
  96. Dim sh As Shape, shs As Shapes
  97. Set shs = ActiveSelection.Shapes
  98. Dim s As String, size As String
  99. For Each sh In shs
  100. sh.SizeWidth = sx
  101. sh.SizeHeight = sy
  102. Next sh
  103. API.EndOpt
  104. End Function
  105. '// 批量设置物件尺寸整数
  106. Public Function Size_to_Integer()
  107. If 0 = ActiveSelectionRange.Count Then Exit Function
  108. API.BeginOpt
  109. '// 修改变形尺寸基准
  110. ActiveDocument.ReferencePoint = cdrCenter
  111. Dim sh As Shape, shs As Shapes
  112. Set shs = ActiveSelection.Shapes
  113. Dim s As String, size As String
  114. For Each sh In shs
  115. size = Int(sh.SizeWidth + 0.5) & "x" & Int(sh.SizeHeight + 0.5) & "mm"
  116. sh.SetSize Int(sh.SizeWidth + 0.5), Int(sh.SizeHeight + 0.5)
  117. s = s & size & vbNewLine
  118. Next sh
  119. API.WriteClipBoard s
  120. API.EndOpt
  121. MsgBox "Object Size Information To Clipboard:" & vbNewLine & s & vbNewLine
  122. End Function
  123. '// 设置物件页面居中
  124. Public Function Align_Page_Center()
  125. If 0 = ActiveSelectionRange.Count Then Exit Function
  126. '// 实践应用: 选择物件群组,页面设置物件大小,物件页面居中
  127. API.BeginOpt
  128. Dim OrigSelection As ShapeRange, sh As Shape
  129. Set OrigSelection = ActiveSelectionRange
  130. Set sh = OrigSelection.Group
  131. ActivePage.SetSize Int(sh.SizeWidth + 0.9), Int(sh.SizeHeight + 0.9)
  132. #If VBA7 Then
  133. ActiveDocument.ClearSelection
  134. sh.AddToSelection
  135. ActiveSelection.AlignAndDistribute 3, 3, 2, 0, False, 2
  136. #Else
  137. sh.AlignToPageCenter cdrAlignHCenter + cdrAlignVCenter
  138. #End If
  139. API.EndOpt
  140. End Function
  141. '''/// 使用Python脚本 整理尺寸 提取条码数字 建立二维码 位图转文本 ///'''
  142. Public Function Python_Organize_Size()
  143. On Error GoTo ErrorHandler
  144. mypy = Path & "GMS\LYVBA\Organize_Size.py"
  145. cmd_line = "pythonw " & Chr(34) & mypy & Chr(34)
  146. Shell cmd_line
  147. ErrorHandler:
  148. End Function
  149. Public Function Python_Get_Barcode_Number()
  150. On Error GoTo ErrorHandler
  151. mypy = Path & "GMS\LYVBA\Get_Barcode_Number.py"
  152. cmd_line = "pythonw " & Chr(34) & mypy & Chr(34)
  153. Shell cmd_line
  154. ErrorHandler:
  155. End Function
  156. Public Function Python_BITMAP()
  157. On Error GoTo ErrorHandler
  158. mypy = Path & "GMS\LYVBA\BITMAP.py"
  159. cmd_line = "pythonw " & Chr(34) & mypy & Chr(34)
  160. Shell cmd_line
  161. ErrorHandler:
  162. End Function
  163. Public Function Python_BITMAP2()
  164. On Error GoTo ErrorHandler
  165. Bitmap = "C:\TSP\BITMAP.exe"
  166. Shell Bitmap
  167. ErrorHandler:
  168. End Function
  169. Public Function Python_Make_QRCode()
  170. On Error GoTo ErrorHandler
  171. mypy = Path & "GMS\LYVBA\Make_QRCode.py"
  172. cmd_line = "pythonw " & Chr(34) & mypy & Chr(34)
  173. Shell cmd_line
  174. ErrorHandler:
  175. End Function
  176. '// QRCode二维码制作
  177. Public Function QRCode_replace()
  178. On Error GoTo ErrorHandler
  179. API.BeginOpt
  180. Dim image_path As String
  181. image_path = API.GetClipBoardString
  182. ActiveDocument.ReferencePoint = cdrCenter
  183. Dim sh As Shape, shs As Shapes, cs As Shape
  184. Dim X As Double, Y As Double
  185. Set shs = ActiveSelection.Shapes
  186. cnt = 0
  187. For Each sh In shs
  188. If cnt = 0 Then
  189. ActiveDocument.ClearSelection
  190. ActiveLayer.Import image_path
  191. Set sc = ActiveSelection
  192. cnt = 1
  193. Else
  194. sc.Duplicate 0, 0
  195. End If
  196. sh.GetPosition X, Y
  197. sc.SetPosition X, Y
  198. sh.GetSize X, Y
  199. sc.SetSize X, Y
  200. sh.Delete
  201. Next sh
  202. ErrorHandler:
  203. API.EndOpt
  204. End Function
  205. '// QRCode二维码转矢量图
  206. Public Function QRCode_to_Vector()
  207. On Error GoTo ErrorHandler
  208. Set sr = ActiveSelectionRange
  209. With sr(1).Bitmap.Trace(cdrTraceHighQualityImage)
  210. .TraceType = cdrTraceHighQualityImage
  211. .Smoothing = 50 '数值小则平滑,数值大则细节多
  212. .RemoveBackground = False
  213. .DeleteOriginalObject = True
  214. .Finish
  215. End With
  216. Exit Function
  217. ErrorHandler:
  218. On Error Resume Next
  219. End Function
  220. '''//// 选择多物件,组合然后拆分线段,为角线爬虫准备 ////'''
  221. Public Function Split_Segment()
  222. On Error GoTo ErrorHandler
  223. API.BeginOpt
  224. Dim ssr As ShapeRange, s As Shape
  225. Dim nr As NodeRange, nd As Node
  226. Set ssr = ActiveSelectionRange
  227. Set s = ssr.UngroupAllEx.Combine
  228. Set nr = s.Curve.Nodes.all
  229. nr.BreakApart
  230. s.BreakApartEx
  231. ' For Each nd In nr
  232. ' nd.BreakApart
  233. ' Next nd
  234. ErrorHandler:
  235. API.EndOpt
  236. End Function
  237. '''//// 标记画框 支持容差 ////'''
  238. Public Function Mark_CreateRectangle(expand As Boolean)
  239. On Error GoTo ErrorHandler
  240. API.BeginOpt
  241. ActiveDocument.ReferencePoint = cdrBottomLeft
  242. Dim ssr As ShapeRange
  243. Dim sh As Shape, tr As Double
  244. Set ssr = ActiveSelectionRange
  245. tr = 0
  246. If GlobalUserData.Exists("Tolerance", 1) Then
  247. tr = Val(GlobalUserData("Tolerance", 1))
  248. End If
  249. For Each sh In ssr
  250. If expand = False Then
  251. mark_shape sh
  252. Else
  253. mark_shape_expand sh, tr
  254. End If
  255. Next sh
  256. ErrorHandler:
  257. API.EndOpt
  258. End Function
  259. Private Function mark_shape_expand(sh As Shape, tr As Double)
  260. Dim s As Shape
  261. Dim X As Double, Y As Double, w As Double, h As Double, r As Double
  262. sh.GetBoundingBox X, Y, w, h
  263. X = X - tr: Y = Y - tr: w = w + 2 * tr: h = h + 2 * tr
  264. r = Max(w, h) / Min(w, h) / 30 * Math.Sqr(w * h)
  265. If w < h Then
  266. Set s = ActiveLayer.CreateRectangle2(X - r, Y, w + 2 * r, h)
  267. Else
  268. Set s = ActiveLayer.CreateRectangle2(X, Y - r, w, h + 2 * r)
  269. End If
  270. s.Outline.SetProperties Color:=CreateRGBColor(0, 255, 0)
  271. End Function
  272. Private Function mark_shape(sh As Shape)
  273. Dim s As Shape
  274. Dim X As Double, Y As Double, w As Double, h As Double
  275. sh.GetBoundingBox X, Y, w, h, True
  276. Set s = ActiveLayer.CreateRectangle2(X, Y, w, h)
  277. s.Outline.SetProperties Color:=CreateRGBColor(0, 255, 0)
  278. End Function
  279. Private Function Max(ByVal a, ByVal b)
  280. If a < b Then
  281. a = b
  282. End If
  283. Max = a
  284. End Function
  285. Private Function Min(ByVal a, ByVal b)
  286. If a > b Then
  287. a = b
  288. End If
  289. Min = a
  290. End Function
  291. '''//// 批量组合合并 ////'''
  292. Public Function Batch_Combine()
  293. On Error GoTo ErrorHandler
  294. API.BeginOpt
  295. Dim ssr As ShapeRange, sh As Shape
  296. Set ssr = ActiveSelectionRange
  297. For Each sh In ssr
  298. sh.UngroupAllEx.Combine
  299. Next sh
  300. ErrorHandler:
  301. API.EndOpt
  302. End Function
  303. '''//// 一键拆开多行组合的文字字符 ////''' ''' 本功能由群友半缘君赞助发行 '''
  304. Public Function Take_Apart_Character()
  305. On Error GoTo ErrorHandler
  306. API.BeginOpt
  307. ActiveDocument.ReferencePoint = cdrBottomLeft
  308. Dim ssr As ShapeRange
  309. Dim s1 As Shape, sh As Shape, s As Shape
  310. Dim tr As Double
  311. Set ssr = ActiveSelectionRange
  312. '// 记忆选择范围
  313. Dim X As Double, Y As Double, w As Double, h As Double
  314. ssr.GetBoundingBox X, Y, w, h
  315. Set s1 = ActiveLayer.CreateRectangle2(X, Y, w, h)
  316. '// 解散群组,先组合,再散开
  317. Set s = ssr.UngroupAllEx.Combine
  318. Set ssr = s.BreakApartEx
  319. '// 读取容差值
  320. tr = 0
  321. If GlobalUserData.Exists("Tolerance", 1) Then
  322. tr = Val(GlobalUserData("Tolerance", 1))
  323. End If
  324. '// 标记画框,选择标记框
  325. For Each sh In ssr
  326. mark_shape_expand sh, tr
  327. Next sh
  328. Set ssr = ActivePage.Shapes.FindShapes(Query:="@colors.find(RGB(0, 255, 0))")
  329. ActiveDocument.ClearSelection
  330. ssr.AddToSelection
  331. '// 调用 智能群组 后删除标记画框
  332. SmartGroup.Smart_Group
  333. ActiveDocument.BeginCommandGroup: Application.Optimization = True
  334. ssr.Delete
  335. Set sh = ActivePage.SelectShapesFromRectangle(s1.LeftX, s1.TopY, s1.RightX, s1.BottomY, False)
  336. ' sh.Shapes.All.Group
  337. s1.Delete
  338. '// 通过s1矩形范围选择群组后合并组合
  339. For Each s In sh.Shapes
  340. s.UngroupAllEx.Combine
  341. Next s
  342. ErrorHandler:
  343. API.EndOpt
  344. End Function
  345. '''//// 简单一刀切 识别群组 ////''' ''' 本功能由群友宏瑞广告赞助发行 '''
  346. Public Function Single_Line()
  347. If 0 = ActiveSelectionRange.Count Then Exit Function
  348. On Error GoTo ErrorHandler
  349. API.BeginOpt
  350. Dim cm(2) As Color
  351. Set cm(0) = CreateRGBColor(0, 255, 0) ' RGB 绿
  352. Set cm(1) = CreateRGBColor(255, 0, 0) ' RGB 红
  353. Dim ssr As ShapeRange
  354. Dim SrNew As New ShapeRange
  355. Dim s As Shape, s1 As Shape, line As Shape, line2 As Shape
  356. Dim cnt As Integer
  357. cnt = 1
  358. If 1 = ActiveSelectionRange.Count Then
  359. Set ssr = ActiveSelectionRange(1).UngroupAllEx
  360. Else
  361. Set ssr = ActiveSelectionRange
  362. End If
  363. '// 记忆选择范围
  364. Dim X As Double, Y As Double, w As Double, h As Double
  365. ssr.GetBoundingBox X, Y, w, h
  366. Set s1 = ActiveLayer.CreateRectangle2(X, Y, w, h)
  367. s1.Outline.SetProperties Color:=cm(0)
  368. SrNew.Add s1
  369. #If VBA7 Then
  370. ' ssr.sort " @shape1.top>@shape2.top"
  371. ssr.Sort " @shape1.left<@shape2.left"
  372. #Else
  373. ' X4 不支持 ShapeRange.sort
  374. #End If
  375. '// 相交 Set line2 = line.Intersect(s, True, True)
  376. '// 判断相交 line.Curve.IntersectsWith(s.Curve)
  377. For Each s In ssr
  378. If cnt > 1 Then
  379. s.ConvertToCurves
  380. Set line = ActiveLayer.CreateLineSegment(s.LeftX, s.TopY, s.LeftX, s.TopY - s.SizeHeight)
  381. line.Outline.SetProperties Color:=cm(1)
  382. SrNew.Add line
  383. End If
  384. cnt = cnt + 1
  385. Next s
  386. SrNew.Group
  387. ErrorHandler:
  388. API.EndOpt
  389. End Function
  390. Public Function Single_Line_Vertical()
  391. If 0 = ActiveSelectionRange.Count Then Exit Function
  392. On Error GoTo ErrorHandler
  393. API.BeginOpt
  394. Dim cm(2) As Color
  395. Set cm(0) = CreateRGBColor(0, 255, 0) ' RGB 绿
  396. Set cm(1) = CreateRGBColor(255, 0, 0) ' RGB 红
  397. Dim ssr As ShapeRange
  398. Dim SrNew As New ShapeRange
  399. Dim s As Shape, s1 As Shape, line As Shape, line2 As Shape
  400. Dim cnt As Integer
  401. cnt = 1
  402. If 1 = ActiveSelectionRange.Count Then
  403. Set ssr = ActiveSelectionRange(1).UngroupAllEx
  404. Else
  405. Set ssr = ActiveSelectionRange
  406. End If
  407. '// 记忆选择范围
  408. Dim X As Double, Y As Double, w As Double, h As Double
  409. ssr.GetBoundingBox X, Y, w, h
  410. Set s1 = ActiveLayer.CreateRectangle2(X, Y, w, h)
  411. s1.Outline.SetProperties Color:=cm(0)
  412. SrNew.Add s1
  413. #If VBA7 Then
  414. ssr.Sort " @shape1.top>@shape2.top"
  415. #Else
  416. ' X4 不支持 ShapeRange.sort
  417. #End If
  418. For Each s In ssr
  419. If cnt > 1 Then
  420. s.ConvertToCurves
  421. Set line = ActiveLayer.CreateLineSegment(s.LeftX, s.TopY, s.RightX, s.TopY)
  422. line.Outline.SetProperties Color:=cm(1)
  423. SrNew.Add line
  424. End If
  425. cnt = cnt + 1
  426. Next s
  427. SrNew.Group
  428. ErrorHandler:
  429. API.EndOpt
  430. End Function
  431. Public Function Single_Line_LastNode()
  432. If 0 = ActiveSelectionRange.Count Then Exit Function
  433. On Error GoTo ErrorHandler
  434. API.BeginOpt
  435. Dim cm(2) As Color
  436. Set cm(0) = CreateRGBColor(0, 255, 0) ' RGB 绿
  437. Set cm(1) = CreateRGBColor(255, 0, 0) ' RGB 红
  438. Dim ssr As ShapeRange
  439. Dim SrNew As New ShapeRange
  440. Dim s As Shape, s1 As Shape, line As Shape, line2 As Shape
  441. Dim cnt As Integer
  442. cnt = 1
  443. If 1 = ActiveSelectionRange.Count Then
  444. Set ssr = ActiveSelectionRange(1).UngroupAllEx
  445. Else
  446. Set ssr = ActiveSelectionRange
  447. End If
  448. ' 记忆选择范围
  449. Dim X As Double, Y As Double, w As Double, h As Double
  450. ssr.GetBoundingBox X, Y, w, h
  451. Set s1 = ActiveLayer.CreateRectangle2(X, Y, w, h)
  452. s1.Outline.SetProperties Color:=cm(0)
  453. SrNew.Add s1
  454. #If VBA7 Then
  455. ssr.Sort " @shape1.left<@shape2.left"
  456. #Else
  457. ' X4 不支持 ShapeRange.sort
  458. #End If
  459. Dim nr As NodeRange
  460. For Each s In ssr
  461. If cnt > 1 Then
  462. Set nr = s.DisplayCurve.Nodes.all
  463. Set line = ActiveLayer.CreateLineSegment(nr.FirstNode.PositionX, nr.FirstNode.PositionY, nr.LastNode.PositionX, nr.LastNode.PositionY)
  464. line.Outline.SetProperties Color:=cm(1)
  465. SrNew.Add line
  466. End If
  467. cnt = cnt + 1
  468. Next s
  469. SrNew.Group
  470. ErrorHandler:
  471. API.EndOpt
  472. End Function
  473. '''//// 选择范围画框 ////'''
  474. Public Function Mark_Range_Box()
  475. If 0 = ActiveSelectionRange.Count Then Exit Function
  476. ActiveDocument.Unit = cdrMillimeter
  477. Dim s1 As Shape, ssr As ShapeRange
  478. Set ssr = ActiveSelectionRange
  479. Dim X As Double, Y As Double, w As Double, h As Double
  480. ssr.GetBoundingBox X, Y, w, h
  481. Set s1 = ActiveLayer.CreateRectangle2(X, Y, w, h)
  482. s1.Outline.SetProperties Color:=CreateRGBColor(0, 255, 0) '// RGB 绿
  483. End Function
  484. '''//// 快速颜色选择 ////'''
  485. Function quickColorSelect()
  486. Dim X As Double, Y As Double
  487. Dim s As Shape, s1 As Shape
  488. Dim sr As ShapeRange, sr2 As ShapeRange
  489. Dim Shift As Long, bClick As Boolean
  490. Dim c As New Color, c2 As New Color
  491. EventsEnabled = False
  492. Set sr = ActivePage.Shapes.FindShapes(Query:="@fill.type = 'uniform'")
  493. ActiveDocument.ClearSelection
  494. bClick = False
  495. While Not bClick
  496. On Error Resume Next
  497. bClick = ActiveDocument.GetUserClick(X, Y, Shift, 10, False, cdrCursorPickNone)
  498. If Not bClick Then
  499. Set s = ActivePage.SelectShapesAtPoint(X, Y, False)
  500. Set s = s.Shapes.Last
  501. c2.CopyAssign s.Fill.UniformColor
  502. Set sr2 = New ShapeRange
  503. For Each s1 In sr.Shapes
  504. c.CopyAssign s1.Fill.UniformColor
  505. If c.IsSame(c2) Then
  506. sr2.Add s1
  507. End If
  508. Next s1
  509. sr2.CreateSelection
  510. ActiveWindow.Refresh
  511. End If
  512. Wend
  513. EventsEnabled = True
  514. End Function
  515. '''//// 切割图形-垂直分割-水平分割 ////'''
  516. Function divideVertically()
  517. If 0 = ActiveSelectionRange.Count Then Exit Function
  518. On Error GoTo ErrorHandler
  519. ActiveDocument.BeginCommandGroup: Application.Optimization = True
  520. cutInHalf 1
  521. ActiveDocument.EndCommandGroup
  522. Application.Optimization = False
  523. ActiveWindow.Refresh: Application.Refresh
  524. Exit Function
  525. ErrorHandler:
  526. Application.Optimization = False
  527. On Error Resume Next
  528. End Function
  529. Function divideHorizontally()
  530. If 0 = ActiveSelectionRange.Count Then Exit Function
  531. On Error GoTo ErrorHandler
  532. ActiveDocument.BeginCommandGroup: Application.Optimization = True
  533. cutInHalf 2
  534. ActiveDocument.EndCommandGroup
  535. Application.Optimization = False
  536. ActiveWindow.Refresh: Application.Refresh
  537. Exit Function
  538. ErrorHandler:
  539. Application.Optimization = False
  540. On Error Resume Next
  541. End Function
  542. Private Function cutInHalf(Optional method As Integer)
  543. Dim s As Shape, rect As Shape, rect2 As Shape
  544. Dim trimmed1 As Shape, trimmed2 As Shape
  545. Dim X As Double, Y As Double, w As Double, h As Double
  546. Dim vBool As Boolean
  547. Dim leeway As Double
  548. Dim sr As ShapeRange, sr2 As New ShapeRange
  549. vBool = True
  550. If method = 2 Then
  551. vBool = False
  552. End If
  553. leeway = 0.1
  554. Set sr = ActiveSelectionRange
  555. ActiveDocument.BeginCommandGroup "Cut in half"
  556. For Each s In sr
  557. s.GetBoundingBox X, Y, w, h
  558. If (vBool) Then
  559. 'vertical slice
  560. Set rect = ActiveLayer.CreateRectangle2(X - leeway, Y - leeway, (w / 2) + leeway, h + (leeway * 2))
  561. Set rect2 = ActiveLayer.CreateRectangle2(X + (w / 2), Y - leeway, (w / 2) + leeway, h + (leeway * 2))
  562. Else
  563. Set rect = ActiveLayer.CreateRectangle2(X - leeway, Y - leeway, w + (leeway * 2), (h / 2) + leeway)
  564. Set rect2 = ActiveLayer.CreateRectangle2(X - leeway, Y + (h / 2), w + (leeway * 2), (h / 2) + leeway)
  565. End If
  566. Set trimmed1 = rect.Intersect(s, True, True)
  567. rect.Delete
  568. Set trimmed2 = rect2.Intersect(s, True, True)
  569. s.Delete
  570. rect2.Delete
  571. sr2.Add trimmed1
  572. sr2.Add trimmed2
  573. Next s
  574. ActiveDocument.EndCommandGroup
  575. sr2.CreateSelection
  576. End Function
  577. '// 批量多页居中-遍历批量物件,放置物件到页面
  578. Public Function Batch_Align_Page_Center()
  579. If 0 = ActiveSelectionRange.Count Then Exit Function
  580. On Error GoTo ErrorHandler
  581. API.BeginOpt
  582. Set sr = ActiveSelectionRange
  583. total = sr.Count
  584. '// 建立多页面
  585. Set doc = ActiveDocument
  586. doc.AddPages (total - 1)
  587. #If VBA7 Then
  588. sr.Sort " @shape1.Top * 100 - @shape1.Left > @shape2.Top * 100 - @shape2.Left"
  589. #Else
  590. ' X4 不支持 ShapeRange.sort
  591. #End If
  592. Dim sh As Shape
  593. '// 遍历批量物件,放置物件到页面
  594. For i = 1 To sr.Count
  595. doc.Pages(i).Activate
  596. Set sh = sr.Shapes(i)
  597. ActivePage.SetSize Int(sh.SizeWidth + 0.9), Int(sh.SizeHeight + 0.9)
  598. '// 物件居中页面
  599. #If VBA7 Then
  600. ActiveDocument.ClearSelection
  601. sh.AddToSelection
  602. ActiveSelection.AlignAndDistribute 3, 3, 2, 0, False, 2
  603. #Else
  604. sh.AlignToPageCenter cdrAlignHCenter + cdrAlignVCenter
  605. #End If
  606. Next i
  607. ErrorHandler:
  608. API.EndOpt
  609. End Function
  610. '// 安全线: 点击一次建立辅助线,再调用清除参考线
  611. Public Function guideangle(actnumber As ShapeRange, cardblood As Integer)
  612. Dim sr As ShapeRange
  613. Set sr = ActiveDocument.MasterPage.GuidesLayer.FindShapes(Type:=cdrGuidelineShape)
  614. If sr.Count <> 0 Then
  615. sr.Delete
  616. Exit Function
  617. End If
  618. If 0 = ActiveSelectionRange.Count Then Exit Function
  619. ActiveDocument.Unit = cdrMillimeter
  620. With actnumber
  621. Set s1 = ActiveDocument.MasterPage.GuidesLayer.CreateGuideAngle(0, .TopY - cardblood, 0#)
  622. Set s1 = ActiveDocument.MasterPage.GuidesLayer.CreateGuideAngle(0, .BottomY + cardblood, 0#)
  623. Set s1 = ActiveDocument.MasterPage.GuidesLayer.CreateGuideAngle(.LeftX + cardblood, 0, 90#)
  624. Set s1 = ActiveDocument.MasterPage.GuidesLayer.CreateGuideAngle(.RightX - cardblood, 0, 90#)
  625. End With
  626. End Function
  627. '// 标注尺寸 批量简单标注数字
  628. Public Function Simple_Label_Numbers()
  629. API.BeginOpt
  630. Set sr = ActiveSelectionRange
  631. For Each s In sr.Shapes
  632. X = s.CenterX: Y = s.TopY
  633. sw = s.SizeWidth: sh = s.SizeHeight
  634. text = Int(sw + 0.5) & "x" & Int(sh + 0.5) & "mm"
  635. Set s = ActiveLayer.CreateArtisticText(0, 0, text)
  636. s.CenterX = X: s.BottomY = Y + 5
  637. Next
  638. API.EndOpt
  639. End Function
  640. '// 修复圆角缺角到直角
  641. Public Function corner_off()
  642. API.BeginOpt
  643. Dim os As ShapeRange
  644. Dim s As Shape, fir As Shape, ci As Shape
  645. Dim nd As Node, nds As Node, nde As Node
  646. Set os = ActiveSelectionRange
  647. On Error GoTo errn
  648. selec = False
  649. If os.Shapes.Count = 1 Then
  650. Set s = os.FirstShape
  651. If Not s.Curve Is Nothing Then
  652. For Each nd In s.Curve.Nodes
  653. If nd.Selected Then
  654. selec = True
  655. Exit For
  656. End If
  657. Next nd
  658. End If
  659. End If
  660. If os.Shapes.Count > 1 Or Not selec Then
  661. os.ConvertToCurves
  662. For Each s In os.Shapes
  663. Set nds = Nothing
  664. Set nde = Nothing
  665. For k = 1 To 3
  666. For i = 1 To s.Curve.Nodes.Count
  667. If i <= s.Curve.Nodes.Count Then
  668. Set nd = s.Curve.Nodes(i)
  669. If Not nd.NextSegment Is Nothing And Not nd.PrevSegment Is Nothing Then
  670. If Abs(nd.PrevSegment.Length - nd.NextSegment.Length) < (nd.PrevSegment.Length + nd.NextSegment.Length) / 30 And nd.PrevSegment.Type = cdrCurveSegment And nd.NextSegment.Type = cdrCurveSegment Then
  671. corner_off_make s, nd.Previous, nd.Next
  672. ElseIf Not nd.Next.NextSegment Is Nothing Then
  673. If (nd.PrevSegment.Type = cdrLineSegment Or Abs(Abs(nd.PrevSegment.StartingControlPointAngle - nd.PrevSegment.EndingControlPointAngle) - 180) < 1) _
  674. And (nd.Next.NextSegment.Type = cdrLineSegment Or Abs(Abs(nd.Next.NextSegment.StartingControlPointAngle - nd.Next.NextSegment.EndingControlPointAngle) - 180) < 1) _
  675. And nd.NextSegment.Type = cdrCurveSegment Then
  676. corner_off_make s, nd, nd.Next
  677. End If
  678. End If
  679. End If
  680. End If
  681. Next i
  682. Next k
  683. Next s
  684. ElseIf os.Shapes.Count = 1 And selec Then
  685. Set nds = Nothing
  686. Set nde = Nothing
  687. For Each nd In s.Curve.Nodes
  688. If Not nd.Selected And Not nd.Next.Selected Then Exit For
  689. Next nd
  690. If Not nd Is s.Curve.Nodes.Last Then
  691. For i = 1 To s.Curve.Nodes.Count
  692. Set nd = nd.Next
  693. If Not nde Is Nothing And Not nds Is Nothing And Not nd.Selected Then Exit For
  694. If Not nds Is Nothing And nd.Selected Then Set nde = nd
  695. If nde Is Nothing And nds Is Nothing And nd.Selected Then Set nds = nd
  696. Next i
  697. If Not nds Is Nothing And Not nde Is Nothing Then
  698. 'ActiveLayer.CreateEllipse2 nds.PositionX, nds.PositionY, nde.PrevSegment.Length / 4
  699. 'ActiveLayer.CreateEllipse2 nde.PositionX, nde.PositionY, nde.PrevSegment.Length / 4
  700. corner_off_make s, nds, nde
  701. End If
  702. End If
  703. End If
  704. errn:
  705. API.EndOpt
  706. End Function
  707. Private Function corner_off_make(s As Shape, nds As Node, nde As Node)
  708. Dim l1 As Shape, l2 As Shape
  709. Dim os As ShapeRange
  710. Dim ss As Shape
  711. Set l1 = ActiveLayer.CreateLineSegment(nds.PositionX, nds.PositionY, nds.PositionX + s.SizeWidth * 3, nds.PositionY)
  712. l1.RotationCenterX = nds.PositionX
  713. l1.RotationAngle = nds.PrevSegment.EndingControlPointAngle + 180
  714. Set l2 = ActiveLayer.CreateLineSegment(nde.PositionX, nde.PositionY, nde.PositionX + s.SizeWidth * 3, nde.PositionY)
  715. l2.RotationCenterX = nde.PositionX
  716. l2.RotationAngle = nde.NextSegment.StartingControlPointAngle + 180
  717. Set lcross = l2.Curve.Segments.First.GetIntersections(l1.Curve.Segments.First)
  718. If lcross.Count > 0 Then
  719. cx = lcross(1).PositionX
  720. cy = lcross(1).PositionY
  721. sx = nds.PositionX
  722. sy = nds.PositionY
  723. ex = nde.PositionX
  724. ey = nde.PositionY
  725. l1.Curve.Nodes.Last.PositionX = cx
  726. l1.Curve.Nodes.Last.PositionY = cy
  727. l2.Curve.Nodes.Last.PositionX = cx
  728. l2.Curve.Nodes.Last.PositionY = cy
  729. s.Curve.Nodes.Range(Array(nds.AbsoluteIndex, nde.AbsoluteIndex)).BreakApart
  730. Set os = s.BreakApartEx
  731. oscnt = os.Shapes.Count
  732. For Each ss In os.Shapes
  733. If ss.Curve.Nodes.First.PositionX = ex And ss.Curve.Nodes.First.PositionY = ey Then Set s2 = ss
  734. If ss.Curve.Nodes.Last.PositionX = sx And ss.Curve.Nodes.Last.PositionY = sy Then Set s1 = ss
  735. If ss.Curve.Nodes.First.PositionX = sx And ss.Curve.Nodes.First.PositionY = sy Then ss.Delete
  736. Next ss
  737. If s1.Curve.Segments.Last.Type = cdrLineSegment Or Abs(Abs(s1.Curve.Segments.Last.StartingControlPointAngle - s1.Curve.Segments.Last.EndingControlPointAngle) - 180) < 1 Then
  738. s1.Curve.Nodes.Last.PositionX = lcross(1).PositionX
  739. s1.Curve.Nodes.Last.PositionY = lcross(1).PositionY
  740. l1.Delete
  741. Else
  742. Set s1 = l1.Weld(s1)
  743. End If
  744. If oscnt = 2 Then Set s2 = s1
  745. If s2.Curve.Segments.First.Type = cdrLineSegment Or Abs(Abs(s2.Curve.Segments.First.StartingControlPointAngle - s2.Curve.Segments.First.EndingControlPointAngle) - 180) < 1 Then
  746. s2.Curve.Nodes.First.PositionX = lcross(1).PositionX
  747. s2.Curve.Nodes.First.PositionY = lcross(1).PositionY
  748. l2.Delete
  749. Else
  750. Set s2 = l2.Weld(s2)
  751. End If
  752. If oscnt > 2 Then Set s2 = s1.Weld(s2)
  753. s2.CustomCommand "ConvertTo", "JoinCurves", 0.1
  754. Set s = s2
  755. Else
  756. l1.Delete
  757. l2.Delete
  758. End If
  759. End Function
  760. Public Function autogroup(Optional Group As String = "group", Optional shft = 0, Optional sss As Shapes = Nothing, Optional undogroup = True) As ShapeRange
  761. Dim sr As ShapeRange, sr_all As ShapeRange, os As ShapeRange
  762. Dim sp As SubPaths
  763. Dim arr()
  764. Dim s As Shape
  765. If sss Is Nothing Then Set os = ActiveSelectionRange Else Set os = sss.all
  766. On Error GoTo errn
  767. ActiveDocument.BeginCommandGroup: Application.Optimization = True
  768. If ActiveSelection.Shapes.Count > 0 Then
  769. gcnt = os.Shapes.Count
  770. ReDim arr(1 To gcnt, 1 To gcnt)
  771. Set sr_all = ActiveSelectionRange
  772. sr_all.RemoveAll
  773. ReDim arr(1 To gcnt, 1 To gcnt)
  774. ActiveDocument.Unit = cdrTenthMicron
  775. sgap = 10
  776. If shft = 2 Or shft = 3 Or shft = 6 Or shft = 7 Then
  777. os.RemoveAll
  778. For Each s In ActiveSelectionRange.Shapes
  779. os.Add ActivePage.SelectShapesFromRectangle(s.LeftX - sgap, s.BottomY - sgap, s.RightX + sgap, s.TopY + sgap, True)
  780. Next s
  781. End If
  782. For i = 1 To os.Shapes.Count
  783. Set s1 = os.Shapes(i)
  784. arr(i, i) = i
  785. For j = 1 To os.Shapes.Count
  786. Set s2 = os.Shapes(j)
  787. If s2.LeftX < s1.RightX + sgap And s2.RightX > s1.LeftX - sgap And s2.BottomY < s1.TopY + sgap And s2.TopY > s1.BottomY - sgap Then
  788. If shft = 1 Or shft = 3 Or shft = 5 Or shft = 7 Then
  789. Set isec = s1.Intersect(s2)
  790. If Not isec Is Nothing Then
  791. arr(i, j) = j
  792. isec.CreateSelection
  793. isec.Delete
  794. End If
  795. Else
  796. arr(i, j) = j
  797. End If
  798. End If
  799. Next j
  800. Next i
  801. For i = 1 To gcnt
  802. arr = collect_arr(arr, i, i)
  803. Next i
  804. Set sr = ActiveSelectionRange
  805. For i = 1 To gcnt
  806. sr.RemoveAll
  807. inar = 0
  808. For j = 1 To gcnt
  809. If arr(i, j) > 0 Then
  810. sr.Add os.Shapes(j)
  811. inar = inar + 1
  812. End If
  813. Next j
  814. If inar > 1 Then
  815. If Group = "group" Then
  816. If shft < 4 Then sr_all.Add sr.Group
  817. End If
  818. Else
  819. If sr.Shapes.Count > 0 Then sr_all.AddRange sr
  820. End If
  821. Next i
  822. Set autogroup = sr_all
  823. End If
  824. ActiveDocument.EndCommandGroup
  825. Application.Optimization = False
  826. ActiveWindow.Refresh: Application.Refresh
  827. Exit Function
  828. errn:
  829. Application.Optimization = False
  830. End Function
  831. Public Function collect_arr(arr, ci, ki)
  832. lim = UBound(arr)
  833. For k = 1 To lim
  834. If arr(ki, k) > 0 Then
  835. arr(ci, k) = k
  836. If ki <> ci Then arr(ki, k) = Empty
  837. If ci <> k And ki <> k Then arr = collect_arr(arr, ci, k)
  838. End If
  839. Next k
  840. 'If ki <> ci Then arr(ki, ki) = Empty
  841. collect_arr = arr
  842. End Function
  843. '// 两个端点的坐标,为(x1,y1)和(x2,y2) 那么其角度a的tan值: tana=(y2-y1)/(x2-x1)
  844. '// 所以计算arctan(y2-y1)/(x2-x1), 得到其角度值a
  845. '// VB中用atn(), 返回值是弧度,需要 乘以 PI /180
  846. Private Function lineangle(x1, y1, x2, y2) As Double
  847. pi = 4 * VBA.Atn(1) '// 计算圆周率
  848. If x2 = x1 Then
  849. lineangle = 90: Exit Function
  850. End If
  851. lineangle = VBA.Atn((y2 - y1) / (x2 - x1)) / pi * 180
  852. End Function
  853. '// 角度转平
  854. Public Function Angle_to_Horizon()
  855. On Error GoTo ErrorHandler
  856. API.BeginOpt
  857. Set sr = ActiveSelectionRange
  858. Set nr = sr.LastShape.DisplayCurve.Nodes.all
  859. If nr.Count = 2 Then
  860. x1 = nr.FirstNode.PositionX: y1 = nr.FirstNode.PositionY
  861. x2 = nr.LastNode.PositionX: y2 = nr.LastNode.PositionY
  862. a = lineangle(x1, y1, x2, y2): sr.Rotate -a
  863. sr.LastShape.Delete '// 删除参考线
  864. End If
  865. ErrorHandler:
  866. API.EndOpt
  867. End Function
  868. '// 自动旋转角度
  869. Public Function Auto_Rotation_Angle()
  870. On Error GoTo ErrorHandler
  871. API.BeginOpt
  872. ' ActiveDocument.ReferencePoint = cdrCenter
  873. Set sr = ActiveSelectionRange
  874. Set nr = sr.LastShape.DisplayCurve.Nodes.all
  875. If nr.Count = 2 Then
  876. x1 = nr.FirstNode.PositionX: y1 = nr.FirstNode.PositionY
  877. x2 = nr.LastNode.PositionX: y2 = nr.LastNode.PositionY
  878. a = lineangle(x1, y1, x2, y2): sr.Rotate 90 + a
  879. sr.LastShape.Delete '// 删除参考线
  880. End If
  881. ErrorHandler:
  882. API.EndOpt
  883. End Function
  884. '// 交换对象
  885. Public Function Exchange_Object()
  886. Set sr = ActiveSelectionRange
  887. If sr.Count = 2 Then
  888. X = sr.LastShape.CenterX: Y = sr.LastShape.CenterY
  889. sr.LastShape.CenterX = sr.FirstShape.CenterX: sr.LastShape.CenterY = sr.FirstShape.CenterY
  890. sr.FirstShape.CenterX = X: sr.FirstShape.CenterY = Y
  891. End If
  892. End Function
  893. '// 参考线镜像
  894. Public Function Mirror_ByGuide()
  895. On Error GoTo ErrorHandler
  896. API.BeginOpt
  897. Set sr = ActiveSelectionRange
  898. Set nr = sr.LastShape.DisplayCurve.Nodes.all
  899. If nr.Count = 2 Then
  900. byshape = False
  901. x1 = nr.FirstNode.PositionX: y1 = nr.FirstNode.PositionY
  902. x2 = nr.LastNode.PositionX: y2 = nr.LastNode.PositionY
  903. a = lineangle(x1, y1, x2, y2) '// 参考线和水平的夹角 a
  904. sr.Remove sr.Count
  905. ang = 90 - a '// 镜像的旋转角度
  906. For Each s In sr
  907. With s
  908. .Duplicate '// 复制物件保留,然后按 x1,y1 点 旋转
  909. .RotationCenterX = x1
  910. .RotationCenterY = y1
  911. .Rotate ang
  912. If Not byshape Then
  913. lx = .LeftX
  914. .Stretch -1#, 1# '// 通过拉伸完成镜像
  915. .LeftX = lx
  916. .Move (x1 - .LeftX) * 2 - .SizeWidth, 0
  917. .RotationCenterX = x1 '// 之前因为镜像,旋转中心点反了,重置回来
  918. .RotationCenterY = y1
  919. .Rotate -ang
  920. End If
  921. .RotationCenterX = .CenterX '// 重置回旋转中心点为物件中心
  922. .RotationCenterY = .CenterY
  923. End With
  924. Next s
  925. End If
  926. ErrorHandler:
  927. API.EndOpt
  928. End Function
  929. '// 按面积排列计数
  930. Public Function Count_byArea(Space_Width As Double)
  931. If 0 = ActiveSelectionRange.Count Then Exit Function
  932. API.BeginOpt
  933. ActiveDocument.ReferencePoint = cdrCenter
  934. Set ssr = ActiveSelectionRange
  935. cnt = 1
  936. #If VBA7 Then
  937. ssr.Sort "@shape1.width * @shape1.height < @shape2.width * @shape2.height"
  938. #Else
  939. ' X4 不支持 ShapeRange.sort
  940. #End If
  941. Dim Str As String, size As String
  942. For Each sh In ssr
  943. size = Int(sh.SizeWidth + 0.5) & "x" & Int(sh.SizeHeight + 0.5) & "mm"
  944. sh.SetSize Int(sh.SizeWidth + 0.5), Int(sh.SizeHeight + 0.5)
  945. Str = Str & size & vbNewLine
  946. Next sh
  947. ActiveDocument.ReferencePoint = cdrTopLeft
  948. For Each s In ssr
  949. If cnt > 1 Then s.SetPosition ssr(cnt - 1).LeftX, ssr(cnt - 1).BottomY - Space_Width
  950. cnt = cnt + 1
  951. Next s
  952. ' 写文件,可以EXCEL里统计
  953. ' Set fs = CreateObject("Scripting.FileSystemObject")
  954. ' Set f = fs.CreateTextFile("D:\size.txt", True)
  955. ' f.WriteLine str: f.Close
  956. Str = Subtotals(Str)
  957. Debug.Print Str
  958. Dim s1 As Shape
  959. ' Set s1 = ActiveLayer.CreateParagraphText(0, 0, 100, 150, Str, Font:="华文中宋")
  960. X = ssr.FirstShape.LeftX - 100
  961. Y = ssr.FirstShape.TopY
  962. Set s1 = ActiveLayer.CreateParagraphText(X, Y, X + 90, Y - 150, Str, Font:="华文中宋")
  963. API.EndOpt
  964. End Function
  965. '// 实现Excel里分类汇总功能
  966. Private Function Subtotals(Str As String) As String
  967. Dim a, b, d, arr
  968. Str = VBA.Replace(Str, vbNewLine, " ")
  969. Do While InStr(Str, " ")
  970. Str = VBA.Replace(Str, " ", " ")
  971. Loop
  972. arr = Split(Str)
  973. Set d = CreateObject("Scripting.dictionary")
  974. For i = 0 To UBound(arr) - 1
  975. If d.Exists(arr(i)) = True Then
  976. d.Item(arr(i)) = d.Item(arr(i)) + 1
  977. Else
  978. d.Add arr(i), 1
  979. End If
  980. Next
  981. Str = " 规 格" & vbTab & vbTab & vbTab & "数量" & vbNewLine
  982. a = d.keys: b = d.items
  983. For i = 0 To d.Count - 1
  984. ' Debug.Print a(i), b(i)
  985. Str = Str & a(i) & vbTab & vbTab & b(i) & "条" & vbNewLine
  986. Next
  987. Subtotals = Str & "合计总量:" & vbTab & vbTab & vbTab & UBound(arr) & "条" & vbNewLine
  988. End Function