【问题标题】:Why does VBA code run faster when called from a standard module (instead of a userform)?为什么从标准模块(而不是用户窗体)调用 VBA 代码时运行得更快?
【发布时间】:2018-01-01 17:17:49
【问题描述】:

备用标题:为什么按 Esc 会使我的 MS-Word 宏运行得更快

在等待一些代码运行时,我偶然发现了一些有趣的东西。

代码运行缓慢...按 Esc 代码运行很快。示例:

  • 执行后立即按 Esc - 2 秒 完成
  • 根本不要按 Esc - 最多 30 秒 即可完成

对我来说这毫无意义。事实证明,其他人也注意到了类似的行为,例如:

他们已经找到了各种解决方案或变通方法。 然而,这些帖子适用于 MS-Excel; Esc 键似乎具有不同的行为。

In MS-Excel pressing the Esc key 可以(取决于 Application.EnableCancleKey 的设置)中断代码或引发错误(Err 18),或者什么也不做。另一方面,in MS Word no such thing happens,Application.EnableCancleKey 改变了 Ctrl + Pause 的行为。尽管如此,按下 Esc 会显着加快代码执行速度。

除了这种差异之外,我的问题更多地与用户表单中的代码位置有关。例如在我的用户表单中:

Private Sub Cmd_Click()

    Module1.Macro1
    Module1.Macro2
    Module1.Macro3

End Sub

在 64 位版本的 Word 2010 上测试,使用上面的结构明显比这个慢:

用户表单:

Private Sub Cmd_Click()

    Module1.RunMacro123

End Sub

标准模块:

Private Sub RunMacro123()

    Module1.Macro1
    Module1.Macro2
    Module1.Macro3

End Sub

我应该注意以下几点:

  1. 这在 64 位版本的 MS Word 中最为明显,32 位版本使用原始代码似乎运行得相当快(我还没有使用修改后的代码进行测试)
  2. 与第一个链接中的作者一样,我没有使用选择对象等。
  3. 我对代码执行速度为何如此受以下因素影响的任何见解更感兴趣:
    • 按 Esc
    • 将调用从用户窗体移动到标准模块
  4. Macro1、Macro2 和 Macro3 创建和编辑文档样式,并且 (FWIW) 涉及多次读取 INI 文件

附带说明,为了聪明,我尝试使用 sendKeys 发送 Esc 键,但它有没有影响。

编辑 - 代码计时结果:

我最终使用计时器函数来计时代码,我已经实现了一个从这里改编的堆栈类:http://www.tek-tips.com/viewthread.cfm?qid=1468970

我在调用堆栈中添加了一个“绝对”计时器 (debug.print timer - startTime),以便记录每次推送之间的时间,并在每次弹出时重置计时器 (startTime = timer)。这样做使得在 NotePad++ 中比较时间更容易

这让我可以确定将样式应用于文档的子应用样式需要大约 0.04 秒(计时器返回的 NB 值 = 午夜过后的秒数)。

下图显示了代码时序结果的示例。基本上,据我所知,代码执行的延迟来自许多与相同基本任务相关的增量延迟。

由于计时器与调用堆栈一起工作的方式,我不得不测试代码getStyleElement 以确保它不会显着增加额外的时间。我通过直接对代码计时来做到这一点,并且能够确认它运行速度始终如一。

检查其余代码确认问题出在applyStyleFormat(调用getStyleElement)。

样式应用于文档 - 代码结构包括 With 块和 For 循环;像这样:

For i = 1 to Styles.Count
    With aDocument.Styles(i)
        .Font.??? = Something
        ' or .Paragraph.??? = Something
    End With
Next i

我不清楚为什么代码在用户窗体之外运行得更快,或者在按下 Esc 之后运行得更快,但确实如此,而且似乎与修改样式有关...

【问题讨论】:

  • 我建议你在任何地方都放一些debug.print Now & " : place in code",以了解它到底滞后在哪里
  • @ThomasG 我很欣赏你所说的,我可以使用vba.Timer 来找到滞后,并且(虽然很痛苦)我可能会回去这样做 - 但我已经有了解决方案。 .. 我只是不明白为什么解决方案有效,也不明白为什么按 Esc 键会加快代码速度。
  • 我也不明白,正是为了尝试理解它,您应该知道它滞后于哪些指令。计时器在这里没有任何帮助
  • 在这里使用 Timer 会很痛苦,因为每次打印都需要更多说明。执行Debug.print Now [place of code] 更简单且足够。它在几秒钟内完成
  • 不,Win10 Word 64

标签: excel vba ms-word


【解决方案1】:

只是在@Florent Bs 评论上拉动线程,您是否尝试过在单击事件中运行宏之前查看可以禁用的内容?像

Application.EnableEvents = False
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual

'code
Module1.Macro1
Module1.Macro2
Module1.Macro3

Application.EnableEvents = True
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic

只是为了看看事情是否更快?可能还有其他命令可以取消人们可以添加的其他内容。

【讨论】:

  • 感谢您的想法 - 在 MS Word 中(据我所知)没有相当于 Application.EnableEvents 和 Application.Calculation。就屏幕更新而言,这已经被禁用,并且通过 API 阻止了屏幕更新: Private Declare PtrSafe Function LockWindowUpdate Lib "user32" (ByVal hWndLock As LongPtr) As LongPtr 欣赏拉动这个线程可能会暴露问题,但我是什么最感兴趣的是“为什么”......我会根据已经发布的最近测试结果来更新这个问题......干杯,
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-16
  • 1970-01-01
  • 2012-06-29
相关资源
最近更新 更多