1
1

Tools.bas 33 KB

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