【问题标题】:Application.Wait Breaks my CodeApplication.Wait 破坏了我的代码
【发布时间】:2017-09-30 09:10:53
【问题描述】:

原创

我有以下代码为单元格着色以演示毫秒等待时间的使用。但是,当i = 500 代码中断时。我得到的错误是Code Execution has been Interrupted,从 500 到 1000 我必须继续点击继续。我试图将我的代码包装在Application.DisplayAlerts = FalseTrue 中,但它仍然会被中断并且无法完成。我估计随着i 接近1000,这段代码大约需要6 分钟。我不知道是什么原因造成的。我已经完成了我能想到的所有设置,并且它不会持续超过 500 而不会中断。 ms 由1/(1000*24*60*60) 计算得出。

Excel 2007

Sub Kaleidoscope()
Dim r, g, b, i As Integer, ms As Double

ms = 0.0000000115741
For i = 1 To 1000
    r = WorksheetFunction.RandBetween(1, 255)
    g = WorksheetFunction.RandBetween(1, 255)
    b = WorksheetFunction.RandBetween(1, 255)
    Range("A1").Interior.Color = RGB(r, g, b)
    Application.Wait (Now + (ms * i))
Next i

End Sub

提前谢谢你!

更新

@MarcoMarc (stackoverflow.com/a/5823507/5175942) 提供的链接解决了我最初的问题。但是,它似乎仍然没有正确增加。好像它没有等到i = 500 然后似乎每次都停顿1秒。这是您所说的限制,最终不可能等待 1 毫秒吗?无需更改原始代码即可防止破坏。

最后的想法

@JohnMuggins 对我的原始代码进行了很好的调整,并提供了额外的工具来查看幕后的计算。不过,Ultimatley 还必须像 @MacroMarc 一样调用 winAPI 才能将代码暂停不到 1 秒。通过对其他网站的研究和 Stack Overflow,仅使用 VBA 似乎不可能将程序暂停少于 1 秒。它要么以正常速度运行,要么在达到 500 毫秒时四舍五入到 1 秒,并将代码延迟 1 秒而不是 500 毫秒。我的最终演示代码如下,带有@JohnMuggins 调整。

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Sub Kaleidascope()
Dim StartTime As Double
Dim EndTime As Double
Dim ms As Double
Dim i, r, g, b As Integer
Dim count As Long

StartTime = Timer

For i = 1 To 500
    ms = i
    r = WorksheetFunction.RandBetween(1, 255)
    g = WorksheetFunction.RandBetween(1, 255)
    b = WorksheetFunction.RandBetween(1, 255)
    Range("A1").Interior.Color = RGB(r, g, b)
    Sleep ms
    Range("B1").Value = "Time: " & Format(Timer - StartTime, "####.###")
    Range("C1").Value = "ms =  " & Format(ms, "####.####")
    Range("D1").Value = i & " of 500"
Next i

EndTime = Timer - StartTime
Debug.Print Format(EndTime, "####.##")
End Sub

【问题讨论】:

  • For i = 1 To 1000 之后使用DoEvents 看看是否有帮助
  • 使用您的建议 For i = 1 To 1000 DoEvents .... 它仍然在 500 处中断。我确实将它们放在不同的行上。
  • 一定和wait函数的限制有关。我使用以下代码没有问题。 Application.Wait (Now + (0.000001))
  • 这可能是您在循环期间中断执行的情况。我以前也遇到过这种情况。尝试在错误弹出窗口中按 Debug,然后按 Ctrl-Break 两次或更多次。看到这个答案:stackoverflow.com/a/5823507/5175942
  • Now() 似乎只能精确到一秒。尝试运行Dim x As Double: For i = 1 To 10000: x = Now(): Debug.Print i, x: Next,您将看到显示值的跳跃。我相信Wait 也适用于秒。我认为准确等待短期的唯一方法是通过using the Sleep function as suggested by MacroMarc

标签: excel excel-2007 wait vba


【解决方案1】:

您可以使用 winAPI 中的睡眠功能。

模块顶部:

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

然后在你的代码中:

Sleep i ' where i is now in milliseconds

请注意,睡眠会延迟所有 VBA 代码。

【讨论】:

  • 如果不调用 Windows API,我正在收集 excel VBA 无法等待不到 1 秒?
  • 不是说不可能,但睡眠是我唯一使用的方法。睡觉似乎最容易。
  • 唯一与睡眠有关的事情是我必须构建 Windows 检测代码来确定它是 32 位还是 64 位并让它调用正确的函数。这就是为什么我试图仅通过 VBA 来实现这种效果。
  • 这个我做的不多,但是你可以尝试一些条件编译:msdn.microsoft.com/en-us/library/office/gg264421.aspx
【解决方案2】:

0m3r 是正确的。问题出在 application.wait 函数上。请尝试以下做事件例程。

Sub Kaleidoscope()
Dim r, g, b, i As Integer, ms As Double

ms = 0.0000000115741
For i = 1 To 1000
    r = WorksheetFunction.RandBetween(1, 255)
    g = WorksheetFunction.RandBetween(1, 255)
    b = WorksheetFunction.RandBetween(1, 255)
    Range("A1").Interior.Color = RGB(r, g, b)
    Range("A1").Value = i
    For j = Now To (Now + (ms * i))
        DoEvents
    Next j
    
Next i

End Sub

【讨论】:

  • 这是一个创造性的解决方法,但最终并没有完成我想要做的事情。我想通过允许代码比之前的等待时间长 1 毫秒来演示等待功能。这在大约 2 秒内完成,并没有证明我在寻找什么。
  • 然后它花费了应有的两倍。一秒钟只有1000毫秒。麦飞!!! MCFLY!!!!
  • 顺便说一句 - 人眼只能捕捉大约每 30 到 60 毫秒的颜色。
  • 我明白,但是如果你把每毫秒加起来 1、2、3、4、5 等等,以此类推为 500,那就是 125250 毫秒。这相当于 125.25 秒或 2.09 分钟。在i >= 500 将更改率与计时器进行比较时,它在 1 秒处停止。 John 提供的答案在大约 2 秒或 2000 ms
  • For j = Now To (Now + (ms * i)) 每次循环都会增加一天,因此永远不会执行超过一次。
【解决方案3】:

这是我达到你的运行时间 2 分 9 秒目标的唯一方法。

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

'   run time on my computer 2:09:07
'   runs from 6 ms to 751.5 ms
Sub ewhgfsd()
Dim StartTime As Double
Dim EndTime As Double

StartTime = Timer

For i = 1 To 500
    ms = ms + (i * 0.006)
    r = WorksheetFunction.RandBetween(1, 255)
    g = WorksheetFunction.RandBetween(1, 255)
    b = WorksheetFunction.RandBetween(1, 255)
    Range("A1").Interior.Color = RGB(r, g, b)
    Sleep ms
    Range("B1").Value = "Time: " & Format(Timer - StartTime, "####.##")
    Range("C1").Value = "ms =  " & Format(ms, "####.#####")
    Range("D1").Value = i & " of 500"
Next i

EndTime = Timer - StartTime
Debug.Print Format(EndTime, "####.##")
End Sub

【讨论】:

  • 我存储了 j as Double 并从 i = 1 To 500 运行,并将代码计时为 9 秒。随着i 变得越来越大,它仍然没有接近我预期的减速。我知道在非常小的间隔内这几乎是不可想象的,但在 100+ 大关时,我预计会出现明显的放缓。我可以看到此方法有效的唯一方法是确定 j 循环并准确花费 1 秒需要多少次。然后我可以通过在该时间范围内执行可能数十万次的计算来逆向设计一个公式来模拟毫秒。
  • 另外,我的代码乘以 1 毫秒(在 excel 中,1 小时是 1/24/3600/1000 = 1.15741E-08 或 0.0000000115741)。我的代码将这个数字乘以某个整数i 说 2,然后它会给我 Excel 解释的 2 毫秒的十进制值。然后我尝试将这个小数添加到Now,以便它等待 2 毫秒。然后在下一个循环中,它将增加 3 毫秒,然后是 4,依此类推。我预计必须等待 2 分钟才能循环完成 500 次迭代。
  • 对不起,你想多了,你的逻辑不正确。一毫秒是千分之一秒。它不是 0.00000005741 秒。在十进制形式中,毫秒是 0.001。您还在我的回答上打了一个负面标记,这完全符合您的要求。当您将分数乘以整数时,您执行的是除法,而不是加法。因此,我已经尽力帮助您了。祝你好运。
  • 一毫秒代表一天的 0.0000000115741。 (.001 / 60 / 60 / 24) OP 没有给出你的答案——我做到了(因为当我给出它的时候它不起作用)。当您将分数乘以整数(例如 0.0000000115741 * 2)时,您不会执行除法,而是将 1 毫秒乘以 2 以获得 2 毫秒。
  • 现在看你的答案,它仍然不会做OP想要的,但它更接近了。如果将 Sleep ms 更改为 Sleep i 以便第一次迭代等待 1 毫秒,第二次迭代等待 2 毫秒等,并去掉 Range.Value = 语句(每个语句将花费几毫秒,从而破坏时间)我相信你会做OP想要的。然后我将删除我的 dv。 (因为您的答案将与 MacroMarc 的相符。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-14
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多