Tools.bas 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  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. ' sr.MoveToLayer ActiveDocument.DesktopLayer
  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. ' MoveToLayer ActivePage.DesktopLayer
  595. '// 遍历批量物件,放置物件到页面 InsertPagesEx ActivePage
  596. For i = 1 To sr.Count
  597. doc.Pages(i).Activate
  598. Set sh = sr.Shapes(i)
  599. ActivePage.SetSize Int(sh.SizeWidth + 0.9), Int(sh.SizeHeight + 0.9)
  600. '// 物件居中页面
  601. #If VBA7 Then
  602. ActiveDocument.ClearSelection
  603. sh.AddToSelection
  604. sh.MoveToLayer ActivePage.ActiveLayer
  605. ActiveSelection.AlignAndDistribute 3, 3, 2, 0, False, 2
  606. #Else
  607. sh.MoveToLayer doc.Pages(i).ActiveLayer
  608. sh.AlignToPageCenter cdrAlignHCenter + cdrAlignVCenter
  609. #End If
  610. Next i
  611. ErrorHandler:
  612. API.EndOpt
  613. End Function
  614. '// 安全线: 点击一次建立辅助线,再调用清除参考线
  615. Public Function guideangle(actnumber As ShapeRange, cardblood As Integer)
  616. Dim sr As ShapeRange
  617. Set sr = ActiveDocument.MasterPage.GuidesLayer.FindShapes(Type:=cdrGuidelineShape)
  618. If sr.Count <> 0 Then
  619. sr.Delete
  620. Exit Function
  621. End If
  622. If 0 = ActiveSelectionRange.Count Then Exit Function
  623. ActiveDocument.Unit = cdrMillimeter
  624. With actnumber
  625. Set s1 = ActiveDocument.MasterPage.GuidesLayer.CreateGuideAngle(0, .TopY - cardblood, 0#)
  626. Set s1 = ActiveDocument.MasterPage.GuidesLayer.CreateGuideAngle(0, .BottomY + cardblood, 0#)
  627. Set s1 = ActiveDocument.MasterPage.GuidesLayer.CreateGuideAngle(.LeftX + cardblood, 0, 90#)
  628. Set s1 = ActiveDocument.MasterPage.GuidesLayer.CreateGuideAngle(.RightX - cardblood, 0, 90#)
  629. End With
  630. End Function
  631. '// 标注尺寸 批量简单标注数字
  632. Public Function Simple_Label_Numbers()
  633. API.BeginOpt
  634. Set sr = ActiveSelectionRange
  635. For Each s In sr.Shapes
  636. X = s.CenterX: Y = s.TopY
  637. sw = s.SizeWidth: sh = s.SizeHeight
  638. text = Int(sw + 0.5) & "x" & Int(sh + 0.5) & "mm"
  639. Set s = ActiveLayer.CreateArtisticText(0, 0, text)
  640. s.CenterX = X: s.BottomY = Y + 5
  641. Next
  642. API.EndOpt
  643. End Function
  644. '// 修复圆角缺角到直角
  645. Public Function corner_off()
  646. API.BeginOpt
  647. Dim os As ShapeRange
  648. Dim s As Shape, fir As Shape, ci As Shape
  649. Dim nd As Node, nds As Node, nde As Node
  650. Set os = ActiveSelectionRange
  651. On Error GoTo errn
  652. selec = False
  653. If os.Shapes.Count = 1 Then
  654. Set s = os.FirstShape
  655. If Not s.Curve Is Nothing Then
  656. For Each nd In s.Curve.Nodes
  657. If nd.Selected Then
  658. selec = True
  659. Exit For
  660. End If
  661. Next nd
  662. End If
  663. End If
  664. If os.Shapes.Count > 1 Or Not selec Then
  665. os.ConvertToCurves
  666. For Each s In os.Shapes
  667. Set nds = Nothing
  668. Set nde = Nothing
  669. For k = 1 To 3
  670. For i = 1 To s.Curve.Nodes.Count
  671. If i <= s.Curve.Nodes.Count Then
  672. Set nd = s.Curve.Nodes(i)
  673. If Not nd.NextSegment Is Nothing And Not nd.PrevSegment Is Nothing Then
  674. 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
  675. corner_off_make s, nd.Previous, nd.Next
  676. ElseIf Not nd.Next.NextSegment Is Nothing Then
  677. If (nd.PrevSegment.Type = cdrLineSegment Or Abs(Abs(nd.PrevSegment.StartingControlPointAngle - nd.PrevSegment.EndingControlPointAngle) - 180) < 1) _
  678. And (nd.Next.NextSegment.Type = cdrLineSegment Or Abs(Abs(nd.Next.NextSegment.StartingControlPointAngle - nd.Next.NextSegment.EndingControlPointAngle) - 180) < 1) _
  679. And nd.NextSegment.Type = cdrCurveSegment Then
  680. corner_off_make s, nd, nd.Next
  681. End If
  682. End If
  683. End If
  684. End If
  685. Next i
  686. Next k
  687. Next s
  688. ElseIf os.Shapes.Count = 1 And selec Then
  689. Set nds = Nothing
  690. Set nde = Nothing
  691. For Each nd In s.Curve.Nodes
  692. If Not nd.Selected And Not nd.Next.Selected Then Exit For
  693. Next nd
  694. If Not nd Is s.Curve.Nodes.Last Then
  695. For i = 1 To s.Curve.Nodes.Count
  696. Set nd = nd.Next
  697. If Not nde Is Nothing And Not nds Is Nothing And Not nd.Selected Then Exit For
  698. If Not nds Is Nothing And nd.Selected Then Set nde = nd
  699. If nde Is Nothing And nds Is Nothing And nd.Selected Then Set nds = nd
  700. Next i
  701. If Not nds Is Nothing And Not nde Is Nothing Then
  702. 'ActiveLayer.CreateEllipse2 nds.PositionX, nds.PositionY, nde.PrevSegment.Length / 4
  703. 'ActiveLayer.CreateEllipse2 nde.PositionX, nde.PositionY, nde.PrevSegment.Length / 4
  704. corner_off_make s, nds, nde
  705. End If
  706. End If
  707. End If
  708. errn:
  709. API.EndOpt
  710. End Function
  711. Private Function corner_off_make(s As Shape, nds As Node, nde As Node)
  712. Dim l1 As Shape, l2 As Shape
  713. Dim os As ShapeRange
  714. Dim ss As Shape
  715. Set l1 = ActiveLayer.CreateLineSegment(nds.PositionX, nds.PositionY, nds.PositionX + s.SizeWidth * 3, nds.PositionY)
  716. l1.RotationCenterX = nds.PositionX
  717. l1.RotationAngle = nds.PrevSegment.EndingControlPointAngle + 180
  718. Set l2 = ActiveLayer.CreateLineSegment(nde.PositionX, nde.PositionY, nde.PositionX + s.SizeWidth * 3, nde.PositionY)
  719. l2.RotationCenterX = nde.PositionX
  720. l2.RotationAngle = nde.NextSegment.StartingControlPointAngle + 180
  721. Set lcross = l2.Curve.Segments.First.GetIntersections(l1.Curve.Segments.First)
  722. If lcross.Count > 0 Then
  723. cx = lcross(1).PositionX
  724. cy = lcross(1).PositionY
  725. sx = nds.PositionX
  726. sy = nds.PositionY
  727. ex = nde.PositionX
  728. ey = nde.PositionY
  729. l1.Curve.Nodes.Last.PositionX = cx
  730. l1.Curve.Nodes.Last.PositionY = cy
  731. l2.Curve.Nodes.Last.PositionX = cx
  732. l2.Curve.Nodes.Last.PositionY = cy
  733. s.Curve.Nodes.Range(Array(nds.AbsoluteIndex, nde.AbsoluteIndex)).BreakApart
  734. Set os = s.BreakApartEx
  735. oscnt = os.Shapes.Count
  736. For Each ss In os.Shapes
  737. If ss.Curve.Nodes.First.PositionX = ex And ss.Curve.Nodes.First.PositionY = ey Then Set s2 = ss
  738. If ss.Curve.Nodes.Last.PositionX = sx And ss.Curve.Nodes.Last.PositionY = sy Then Set s1 = ss
  739. If ss.Curve.Nodes.First.PositionX = sx And ss.Curve.Nodes.First.PositionY = sy Then ss.Delete
  740. Next ss
  741. If s1.Curve.Segments.Last.Type = cdrLineSegment Or Abs(Abs(s1.Curve.Segments.Last.StartingControlPointAngle - s1.Curve.Segments.Last.EndingControlPointAngle) - 180) < 1 Then
  742. s1.Curve.Nodes.Last.PositionX = lcross(1).PositionX
  743. s1.Curve.Nodes.Last.PositionY = lcross(1).PositionY
  744. l1.Delete
  745. Else
  746. Set s1 = l1.Weld(s1)
  747. End If
  748. If oscnt = 2 Then Set s2 = s1
  749. If s2.Curve.Segments.First.Type = cdrLineSegment Or Abs(Abs(s2.Curve.Segments.First.StartingControlPointAngle - s2.Curve.Segments.First.EndingControlPointAngle) - 180) < 1 Then
  750. s2.Curve.Nodes.First.PositionX = lcross(1).PositionX
  751. s2.Curve.Nodes.First.PositionY = lcross(1).PositionY
  752. l2.Delete
  753. Else
  754. Set s2 = l2.Weld(s2)
  755. End If
  756. If oscnt > 2 Then Set s2 = s1.Weld(s2)
  757. s2.CustomCommand "ConvertTo", "JoinCurves", 0.1
  758. Set s = s2
  759. Else
  760. l1.Delete
  761. l2.Delete
  762. End If
  763. End Function
  764. Public Function autogroup(Optional Group As String = "group", Optional shft = 0, Optional sss As Shapes = Nothing, Optional undogroup = True) As ShapeRange
  765. Dim sr As ShapeRange, sr_all As ShapeRange, os As ShapeRange
  766. Dim sp As SubPaths
  767. Dim arr()
  768. Dim s As Shape
  769. If sss Is Nothing Then Set os = ActiveSelectionRange Else Set os = sss.all
  770. On Error GoTo errn
  771. ActiveDocument.BeginCommandGroup: Application.Optimization = True
  772. If ActiveSelection.Shapes.Count > 0 Then
  773. gcnt = os.Shapes.Count
  774. ReDim arr(1 To gcnt, 1 To gcnt)
  775. Set sr_all = ActiveSelectionRange
  776. sr_all.RemoveAll
  777. ReDim arr(1 To gcnt, 1 To gcnt)
  778. ActiveDocument.Unit = cdrTenthMicron
  779. sgap = 10
  780. If shft = 2 Or shft = 3 Or shft = 6 Or shft = 7 Then
  781. os.RemoveAll
  782. For Each s In ActiveSelectionRange.Shapes
  783. os.Add ActivePage.SelectShapesFromRectangle(s.LeftX - sgap, s.BottomY - sgap, s.RightX + sgap, s.TopY + sgap, True)
  784. Next s
  785. End If
  786. For i = 1 To os.Shapes.Count
  787. Set s1 = os.Shapes(i)
  788. arr(i, i) = i
  789. For j = 1 To os.Shapes.Count
  790. Set s2 = os.Shapes(j)
  791. 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
  792. If shft = 1 Or shft = 3 Or shft = 5 Or shft = 7 Then
  793. Set isec = s1.Intersect(s2)
  794. If Not isec Is Nothing Then
  795. arr(i, j) = j
  796. isec.CreateSelection
  797. isec.Delete
  798. End If
  799. Else
  800. arr(i, j) = j
  801. End If
  802. End If
  803. Next j
  804. Next i
  805. For i = 1 To gcnt
  806. arr = collect_arr(arr, i, i)
  807. Next i
  808. Set sr = ActiveSelectionRange
  809. For i = 1 To gcnt
  810. sr.RemoveAll
  811. inar = 0
  812. For j = 1 To gcnt
  813. If arr(i, j) > 0 Then
  814. sr.Add os.Shapes(j)
  815. inar = inar + 1
  816. End If
  817. Next j
  818. If inar > 1 Then
  819. If Group = "group" Then
  820. If shft < 4 Then sr_all.Add sr.Group
  821. End If
  822. Else
  823. If sr.Shapes.Count > 0 Then sr_all.AddRange sr
  824. End If
  825. Next i
  826. Set autogroup = sr_all
  827. End If
  828. ActiveDocument.EndCommandGroup
  829. Application.Optimization = False
  830. ActiveWindow.Refresh: Application.Refresh
  831. Exit Function
  832. errn:
  833. Application.Optimization = False
  834. End Function
  835. Public Function collect_arr(arr, ci, ki)
  836. lim = UBound(arr)
  837. For k = 1 To lim
  838. If arr(ki, k) > 0 Then
  839. arr(ci, k) = k
  840. If ki <> ci Then arr(ki, k) = Empty
  841. If ci <> k And ki <> k Then arr = collect_arr(arr, ci, k)
  842. End If
  843. Next k
  844. 'If ki <> ci Then arr(ki, ki) = Empty
  845. collect_arr = arr
  846. End Function
  847. '// 两个端点的坐标,为(x1,y1)和(x2,y2) 那么其角度a的tan值: tana=(y2-y1)/(x2-x1)
  848. '// 所以计算arctan(y2-y1)/(x2-x1), 得到其角度值a
  849. '// VB中用atn(), 返回值是弧度,需要 乘以 PI /180
  850. Private Function lineangle(x1, y1, x2, y2) As Double
  851. pi = 4 * VBA.Atn(1) '// 计算圆周率
  852. If x2 = x1 Then
  853. lineangle = 90: Exit Function
  854. End If
  855. lineangle = VBA.Atn((y2 - y1) / (x2 - x1)) / pi * 180
  856. End Function
  857. '// 角度转平
  858. Public Function Angle_to_Horizon()
  859. On Error GoTo ErrorHandler
  860. API.BeginOpt
  861. Set sr = ActiveSelectionRange
  862. Set nr = sr.LastShape.DisplayCurve.Nodes.all
  863. If nr.Count = 2 Then
  864. x1 = nr.FirstNode.PositionX: y1 = nr.FirstNode.PositionY
  865. x2 = nr.LastNode.PositionX: y2 = nr.LastNode.PositionY
  866. a = lineangle(x1, y1, x2, y2): sr.Rotate -a
  867. sr.LastShape.Delete '// 删除参考线
  868. End If
  869. ErrorHandler:
  870. API.EndOpt
  871. End Function
  872. '// 自动旋转角度
  873. Public Function Auto_Rotation_Angle()
  874. On Error GoTo ErrorHandler
  875. API.BeginOpt
  876. ' ActiveDocument.ReferencePoint = cdrCenter
  877. Set sr = ActiveSelectionRange
  878. Set nr = sr.LastShape.DisplayCurve.Nodes.all
  879. If nr.Count = 2 Then
  880. x1 = nr.FirstNode.PositionX: y1 = nr.FirstNode.PositionY
  881. x2 = nr.LastNode.PositionX: y2 = nr.LastNode.PositionY
  882. a = lineangle(x1, y1, x2, y2): sr.Rotate 90 + a
  883. sr.LastShape.Delete '// 删除参考线
  884. End If
  885. ErrorHandler:
  886. API.EndOpt
  887. End Function
  888. '// 交换对象
  889. Public Function Exchange_Object()
  890. Set sr = ActiveSelectionRange
  891. If sr.Count = 2 Then
  892. X = sr.LastShape.CenterX: Y = sr.LastShape.CenterY
  893. sr.LastShape.CenterX = sr.FirstShape.CenterX: sr.LastShape.CenterY = sr.FirstShape.CenterY
  894. sr.FirstShape.CenterX = X: sr.FirstShape.CenterY = Y
  895. End If
  896. End Function
  897. '// 参考线镜像
  898. Public Function Mirror_ByGuide()
  899. On Error GoTo ErrorHandler
  900. API.BeginOpt
  901. Set sr = ActiveSelectionRange
  902. Set nr = sr.LastShape.DisplayCurve.Nodes.all
  903. If nr.Count = 2 Then
  904. byshape = False
  905. x1 = nr.FirstNode.PositionX: y1 = nr.FirstNode.PositionY
  906. x2 = nr.LastNode.PositionX: y2 = nr.LastNode.PositionY
  907. a = lineangle(x1, y1, x2, y2) '// 参考线和水平的夹角 a
  908. sr.Remove sr.Count
  909. ang = 90 - a '// 镜像的旋转角度
  910. For Each s In sr
  911. With s
  912. .Duplicate '// 复制物件保留,然后按 x1,y1 点 旋转
  913. .RotationCenterX = x1
  914. .RotationCenterY = y1
  915. .Rotate ang
  916. If Not byshape Then
  917. lx = .LeftX
  918. .Stretch -1#, 1# '// 通过拉伸完成镜像
  919. .LeftX = lx
  920. .Move (x1 - .LeftX) * 2 - .SizeWidth, 0
  921. .RotationCenterX = x1 '// 之前因为镜像,旋转中心点反了,重置回来
  922. .RotationCenterY = y1
  923. .Rotate -ang
  924. End If
  925. .RotationCenterX = .CenterX '// 重置回旋转中心点为物件中心
  926. .RotationCenterY = .CenterY
  927. End With
  928. Next s
  929. End If
  930. ErrorHandler:
  931. API.EndOpt
  932. End Function
  933. '// 按面积排列计数
  934. Public Function Count_byArea(Space_Width As Double)
  935. If 0 = ActiveSelectionRange.Count Then Exit Function
  936. API.BeginOpt
  937. ActiveDocument.ReferencePoint = cdrCenter
  938. Set ssr = ActiveSelectionRange
  939. cnt = 1
  940. #If VBA7 Then
  941. ssr.Sort "@shape1.width * @shape1.height < @shape2.width * @shape2.height"
  942. #Else
  943. ' X4 不支持 ShapeRange.sort
  944. #End If
  945. Dim Str As String, size As String
  946. For Each sh In ssr
  947. size = Int(sh.SizeWidth + 0.5) & "x" & Int(sh.SizeHeight + 0.5) & "mm"
  948. sh.SetSize Int(sh.SizeWidth + 0.5), Int(sh.SizeHeight + 0.5)
  949. Str = Str & size & vbNewLine
  950. Next sh
  951. ActiveDocument.ReferencePoint = cdrTopLeft
  952. For Each s In ssr
  953. If cnt > 1 Then s.SetPosition ssr(cnt - 1).LeftX, ssr(cnt - 1).BottomY - Space_Width
  954. cnt = cnt + 1
  955. Next s
  956. ' 写文件,可以EXCEL里统计
  957. ' Set fs = CreateObject("Scripting.FileSystemObject")
  958. ' Set f = fs.CreateTextFile("D:\size.txt", True)
  959. ' f.WriteLine str: f.Close
  960. Str = Subtotals(Str)
  961. Debug.Print Str
  962. Dim s1 As Shape
  963. ' Set s1 = ActiveLayer.CreateParagraphText(0, 0, 100, 150, Str, Font:="华文中宋")
  964. X = ssr.FirstShape.LeftX - 100
  965. Y = ssr.FirstShape.TopY
  966. Set s1 = ActiveLayer.CreateParagraphText(X, Y, X + 90, Y - 150, Str, Font:="华文中宋")
  967. API.EndOpt
  968. End Function
  969. '// 实现Excel里分类汇总功能
  970. Private Function Subtotals(Str As String) As String
  971. Dim a, b, d, arr
  972. Str = VBA.Replace(Str, vbNewLine, " ")
  973. Do While InStr(Str, " ")
  974. Str = VBA.Replace(Str, " ", " ")
  975. Loop
  976. arr = Split(Str)
  977. Set d = CreateObject("Scripting.dictionary")
  978. For i = 0 To UBound(arr) - 1
  979. If d.Exists(arr(i)) = True Then
  980. d.Item(arr(i)) = d.Item(arr(i)) + 1
  981. Else
  982. d.Add arr(i), 1
  983. End If
  984. Next
  985. Str = " 规 格" & vbTab & vbTab & vbTab & "数量" & vbNewLine
  986. a = d.keys: b = d.items
  987. For i = 0 To d.Count - 1
  988. ' Debug.Print a(i), b(i)
  989. Str = Str & a(i) & vbTab & vbTab & b(i) & "条" & vbNewLine
  990. Next
  991. Subtotals = Str & "合计总量:" & vbTab & vbTab & vbTab & UBound(arr) & "条" & vbNewLine
  992. End Function