ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 1279|回复: 7

[求助] 如何提高VBA WORD中循环的速度?

[复制链接]

TA的精华主题

TA的得分主题

发表于 2021-2-9 14:37 | 显示全部楼层 |阅读模式
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 lingongzhe 于 2021-2-9 16:23 编辑

如图,我的VBA程序想做到检查RTF文档里是否有三线表跨页显示的情况。用循环table的方式检查具体是哪一页出现了跨页情况。但是当页数很大的时候,运行速度特别慢,例子class.rtf只是将近3000页,就已经要跑27分钟。如何能够提高效率和运行速度呢?
测试文档和我的VBA程序已经上传,求大神帮忙看下,万分感谢!

image.png


image.jpg
代码如下
  1. Private Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
  2. Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
  3. Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
  4. Private Const GWL_STYLE = (-16)
  5. Private Const WS_THICKFRAME As Long = &H40000 '(恢复大小)
  6. Private Const WS_MINIMIZEBOX As Long = &H20000 '(最小化)
  7. Private Const WS_MAXIMIZEBOX As Long = &H10000 '(最大化)

  8. Private Sub UserForm_Initialize()
  9.    Dim hWndForm As Long
  10.    Dim IStyle As Long
  11.    hWndForm = FindWindow("ThunderDFrame", Me.Caption)
  12.    IStyle = GetWindowLong(hWndForm, GWL_STYLE)
  13.    IStyle = IStyle Or WS_THICKFRAME '还原
  14.    IStyle = IStyle Or WS_MINIMIZEBOX '最小化
  15.    IStyle = IStyle Or WS_MAXIMIZEBOX '最大化
  16.    SetWindowLong hWndForm, GWL_STYLE, IStyle
  17. End Sub

  18. Private Sub CommandButton1_Click()
  19.     Application.ScreenUpdating = True
  20.     Application.DisplayAlerts = False
  21.     Dim t As Table, c As Cell
  22.     Dim f As Object
  23.     Dim MyTable As Table
  24.     Dim tabCount, pageCount, cellCount, firstCharPage, lastCharPage As Long
  25.     startTime = Date + Time
  26.     Selection.WholeStory
  27.     Selection.Delete unit:=wdCharacter, Count:=1
  28.     rtfPath = TextBox1.Value
  29.     FName = Dir(rtfPath & "" & "*.rtf")
  30.     n = 0
  31.     For Each f In CreateObject("scripting.FileSystemObject").GetFolder(rtfPath).Files
  32.         If f.Name Like "*.rtf" Then n = n + 1
  33.     Next
  34.    
  35.     '插入表格
  36.     Set MyTable = ThisDocument.Tables.Add(Range:=ThisDocument.Range(Start:=0, End:=0), NumRows:=n + 1, NumColumns:=5)
  37.     With ThisDocument.Tables(1)
  38.         .Columns(1).Width = 125
  39.         .Columns(2).Width = 50
  40.         .Columns(3).Width = 50
  41.         .Columns(4).Width = 40
  42.         .Columns(5).Width = 150
  43.         .Borders.InsideLineStyle = wdLineStyleSingle
  44.         .Borders.OutsideLineStyle = wdLineStyleSingle
  45.         .Cell(Row:=1, Column:=1).Range.InsertAfter Text:="RTF"
  46.         .Cell(Row:=1, Column:=2).Range.InsertAfter Text:="表格数"
  47.         .Cell(Row:=1, Column:=3).Range.InsertAfter Text:="页码数"
  48.         .Cell(Row:=1, Column:=4).Range.InsertAfter Text:="标记"
  49.         .Cell(Row:=1, Column:=5).Range.InsertAfter Text:="跨页页码"
  50.     End With
  51.    
  52.     '实例化word对象
  53.     On Error Resume Next
  54.     Set docApp = CreateObject("Word.Application")
  55.    
  56.     i = 3
  57.     If Len(FName) > 0 Then
  58.         docApp.Documents.Open (rtfPath & "" & FName)
  59.         tabCount = docApp.ActiveDocument.Tables.Count
  60.         pageCount = docApp.Selection.Information(wdNumberOfPagesInDocument)
  61.         '检查跨页
  62.         If tabCount <> pageCount Then
  63.             For Each t In docApp.ActiveDocument.Tables
  64.                 cellCount = t.Range.Cells.Count
  65.                 firstCharPage = t.Range.Cells(1).Range.Characters.First.Information(wdActiveEndPageNumber)
  66.                 lastCharPage = t.Range.Cells(cellCount).Range.Characters.First.Information(wdActiveEndPageNumber)
  67.                 If firstCharPage <> lastCharPage Then
  68.                     With ThisDocument.Tables(1)
  69.                         .Cell(Row:=i, Column:=5).Range.InsertAfter Text:=firstCharPage & "; "
  70.                     End With
  71.                 End If
  72.             Next
  73.         End If
  74.         With ThisDocument.Tables(1)
  75.             .Cell(Row:=2, Column:=1).Range.InsertAfter Text:=FName
  76.             .Cell(Row:=2, Column:=2).Range.InsertAfter Text:=tabCount
  77.             .Cell(Row:=2, Column:=3).Range.InsertAfter Text:=pageCount
  78.         End With
  79.         If tabCount <> pageCount Then
  80.             With ThisDocument.Tables(1)
  81.                 .Cell(Row:=2, Column:=4).Range.InsertAfter Text:="Y"
  82.             End With
  83.             With ThisDocument.Tables(1)
  84.                 .Cell(Row:=2, Column:=1).Range.Font.ColorIndex = wdRed
  85.                 .Cell(Row:=2, Column:=2).Range.Font.ColorIndex = wdRed
  86.                 .Cell(Row:=2, Column:=3).Range.Font.ColorIndex = wdRed
  87.                 .Cell(Row:=2, Column:=4).Range.Font.ColorIndex = wdRed
  88.                 .Cell(Row:=2, Column:=5).Range.Font.ColorIndex = wdRed
  89.             End With
  90.         End If
  91.         pctDone = Format(1 / n, "0.0%")
  92.         With UserForm1
  93.             .Label2.Caption = 0
  94.             .Label2.Caption = pctDone
  95.         End With
  96.         docApp.ActiveDocument.Close False
  97.         Do
  98.             FName = Dir
  99.             If FName <> "" Then
  100.                 docApp.Documents.Open (rtfPath & "" & FName)
  101.                 tabCount = docApp.ActiveDocument.Tables.Count
  102.                 pageCount = docApp.Selection.Information(wdNumberOfPagesInDocument)
  103.                 '检查跨页
  104.                 If tabCount <> pageCount Then
  105.                     For Each t In docApp.ActiveDocument.Tables
  106.                         cellCount = t.Range.Cells.Count
  107.                         firstCharPage = t.Range.Cells(1).Range.Characters.First.Information(wdActiveEndPageNumber)
  108.                         lastCharPage = t.Range.Cells(cellCount).Range.Characters.First.Information(wdActiveEndPageNumber)
  109.                         If firstCharPage <> lastCharPage Then
  110.                             With ThisDocument.Tables(1)
  111.                                 .Cell(Row:=i, Column:=5).Range.InsertAfter Text:=firstCharPage & "; "
  112.                             End With
  113.                         End If
  114.                     Next
  115.                 End If
  116.                 With ThisDocument.Tables(1)
  117.                     .Cell(Row:=i, Column:=1).Range.InsertAfter Text:=FName
  118.                     .Cell(Row:=i, Column:=2).Range.InsertAfter Text:=tabCount
  119.                     .Cell(Row:=i, Column:=3).Range.InsertAfter Text:=pageCount
  120.                 End With
  121.                 If tabCount <> pageCount Then
  122.                     With ThisDocument.Tables(1)
  123.                         .Cell(Row:=i, Column:=4).Range.InsertAfter Text:="Y"
  124.                     End With
  125.                     With ThisDocument.Tables(1)
  126.                         .Cell(Row:=i, Column:=1).Range.Font.ColorIndex = wdRed
  127.                         .Cell(Row:=i, Column:=2).Range.Font.ColorIndex = wdRed
  128.                         .Cell(Row:=i, Column:=3).Range.Font.ColorIndex = wdRed
  129.                         .Cell(Row:=i, Column:=4).Range.Font.ColorIndex = wdRed
  130.                         .Cell(Row:=i, Column:=5).Range.Font.ColorIndex = wdRed
  131.                     End With
  132.                 End If
  133.                 pctDone = Format(i / n, "0.0%")
  134.                 With UserForm1
  135.                     .Label2.Caption = 0
  136.                     .Label2.Caption = pctDone
  137.                 End With
  138.                 i = i + 1
  139.                 docApp.ActiveDocument.Close False
  140.             End If
  141.         Loop Until Len(FName) = 0
  142.     End If
  143.     With UserForm1
  144.         .Label2.Caption = 100
  145.     End With
  146.     Set docApp = Nothing
  147.     Application.DisplayAlerts = True
  148.     endTime = Date + Time
  149.     interval = Format(endTime - startTime, "hh:mm:ss")
  150.     MsgBox "耗时" & interval
  151.     MsgBox "Finished!", 64, " "
  152. End Sub

  153. Private Sub CommandButton2_Click()
  154.     Set objshell = CreateObject("wscript.shell")
  155.     Set DosExec = objshell.Exec("cmd.exe /c " & "taskkill /f /t /im WINWORD.exe")
  156.     Set DosExec = Nothing
  157.     Set objshell = Nothing
  158. End Sub
复制代码


test.7z

470.74 KB, 下载次数: 11

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-2-9 16:31 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
主要就是针对下面的这段代码,求大佬帮忙解决下,万分感谢呢

  1. '检查跨页
  2.                 If tabCount <> pageCount Then
  3.                     For Each t In docApp.ActiveDocument.Tables
  4.                         cellCount = t.Range.Cells.Count
  5.                         firstCharPage = t.Range.Cells(1).Range.Characters.First.Information(wdActiveEndPageNumber)
  6.                         lastCharPage = t.Range.Cells(cellCount).Range.Characters.First.Information(wdActiveEndPageNumber)
  7.                         If firstCharPage <> lastCharPage Then
  8.                             With ThisDocument.Tables(1)
  9.                                 .Cell(Row:=i, Column:=5).Range.InsertAfter Text:=firstCharPage & "; "
  10.                             End With
  11.                         End If
  12.                     Next
  13.                 End If
复制代码

TA的精华主题

TA的得分主题

发表于 2021-2-10 09:01 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-2-10 10:24 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
Jason_WangSS 发表于 2021-2-10 09:01
你的class.rtf文件打开非常慢

对,太大了,现实中我用到的还有是这个文件3-4倍大的文件。
不过我跑过,如果单纯检查class.rtf的页数,需要8分钟。但是要循环遍历每一个表格,就要28分钟了,说明这多出来的20分钟应该就是循环花的时间了。
现实项目里,可能会有5-6个很大的rtf文件,所以这么跑就会很没效率了。
大佬,不知道VBA可以直接从RTF的源码入手做到我这件事情吗,这样是不是就可以以txt的形式打开,速度会有质的飞跃了?

TA的精华主题

TA的得分主题

发表于 2021-2-10 22:10 | 显示全部楼层
可试将Private Sub CommandButton1_Click过程改为如下代码,去掉Application.Visible = False行,用时会多些
  1. Private Sub CommandButton1_Click()
  2.     Dim t As Table
  3.     Dim f As Object
  4.     Dim MyTable As Table
  5.     Dim StartTime As Date, EndTime As Date
  6.     Dim i%, n%, tabCount%, pageCount%, firstCharPage%
  7.     Dim rtfPath$, FName$, pctDone$, interval$
  8.    
  9.     Dim data() As String
  10.     Dim info As String
  11.     Dim tabpageCount As Integer
  12.    
  13.     Application.Visible = False  '界面设为不可见
  14.     Application.ScreenUpdating = False
  15.     Application.DisplayAlerts = False
  16.     StartTime = Date + Time
  17.     rtfPath = TextBox1.Value
  18.     FName = Dir(rtfPath & "" & "*.rtf")
  19.     n = 0
  20.     For Each f In CreateObject("scripting.FileSystemObject").GetFolder(rtfPath).Files
  21.         If f.Name Like "*.rtf" Then n = n + 1
  22.     Next
  23.    
  24.     Do While FName <> Empty
  25.         With Documents.Open(rtfPath & "" & FName)
  26.             ReDim Preserve data(i)
  27.             tabCount = .Tables.Count
  28.             pageCount = .Content.Information(wdNumberOfPagesInDocument)
  29.             If tabCount = 0 Then
  30.                 data(i) = FName & vbTab & vbTab & pageCount
  31.             Else
  32.                 For Each t In .Tables
  33.                     firstCharPage = t.Range.Cells(1).Range.Characters.First.Information(wdActiveEndPageNumber)
  34.                     If t.Range.ComputeStatistics(wdStatisticPages) > 1 Then info = info & firstCharPage & " ; "
  35.                 Next
  36.                 If info = Empty Then
  37.                     data(i) = FName & vbTab & tabCount & vbTab & pageCount
  38.                 Else
  39.                     data(i) = FName & vbTab & tabCount & vbTab & pageCount & vbTab & "Y" & vbTab & info
  40.                 End If
  41.             End If
  42.             info = Empty
  43.             .Close False
  44.         End With
  45.         i = i + 1
  46.         FName = Dir
  47.     Loop
  48.     With ThisDocument.Range(0, 0)
  49.         .Text = "RTF" & vbTab & "表格数" & vbTab & "页码数" & vbTab & "标记" & vbTab & "跨页页码" & vbCrLf & Join(data, vbCrLf)
  50.         .ConvertToTable
  51.     End With
  52.    
  53.     With ThisDocument.Tables(1)
  54.         .Columns(1).Width = 125
  55.         .Columns(2).Width = 50
  56.         .Columns(3).Width = 50
  57.         .Columns(4).Width = 40
  58.         .Columns(5).Width = 150
  59.         .Borders.InsideLineStyle = wdLineStyleSingle
  60.         .Borders.OutsideLineStyle = wdLineStyleSingle
  61.     End With
  62.    
  63.     With UserForm1
  64.         .Label2.Caption = 100
  65.     End With
  66.     Application.Visible = True
  67.     Application.ScreenUpdating = True
  68.     Application.DisplayAlerts = True
  69.     EndTime = Date + Time
  70.     interval = Format(EndTime - StartTime, "hh:mm:ss")
  71.     MsgBox "耗时" & interval
  72.     MsgBox "Finished!", 64, " "
  73. End Sub
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-2-11 11:20 | 显示全部楼层
sylun 发表于 2021-2-10 22:10
可试将Private Sub CommandButton1_Click过程改为如下代码,去掉Application.Visible = False行,用时会多 ...

谢谢大佬,我读一读你的代码,试试哈,万分感谢

TA的精华主题

TA的得分主题

发表于 2021-2-12 08:46 来自手机 | 显示全部楼层
lingongzhe 发表于 2021-2-11 11:20
谢谢大佬,我读一读你的代码,试试哈,万分感谢

,太大了,现实中我用到的还有是这个文件3-4倍大的文件。

建议拆成小文件,或者html或者latex,markdown,就可以用字符串处理了。

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-2-14 18:12 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
zpy2 发表于 2021-2-12 08:46
,太大了,现实中我用到的还有是这个文件3-4倍大的文件。

建议拆成小文件,或者html或者latex,markdow ...

好的好的,这些标记语言,我都不太会,那我得研究研究了,谢谢啦,非常感谢
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-24 00:42 , Processed in 0.034459 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表