如何暂停特定的时间? (Excel/VBA)
Posted
技术标签:
【中文标题】如何暂停特定的时间? (Excel/VBA)【英文标题】:How to pause for specific amount of time? (Excel/VBA) 【发布时间】:2010-12-05 09:31:30 【问题描述】:我有一个包含以下宏的 Excel 工作表。我想每秒循环一次,但如果我能找到执行此操作的函数,我会冒险。不可以吗?
Sub Macro1()
'
' Macro1 Macro
'
Do
Calculate
'Here I want to wait for one second
Loop
End Sub
【问题讨论】:
【参考方案1】:使用Wait method:
Application.Wait Now + #0:00:01#
或(对于 Excel 2010 及更高版本):
Application.Wait Now + #12:00:01 AM#
【讨论】:
我不太确定你的意思,但我推测你想要DoEvents
在这里演示 dailydoseofexcel.com/archives/2005/06/14/stopwatch
@Benoit 和@Keng,可以直接放 1 秒,避免将文本转换为日期。对我来说更干净:Application.Wait(Now + #0:00:01#)
干杯!
该格式在 Excel 2010 中不起作用。但它可以工作:Application.Wait (Now + TimeValue("0:00:01"))
DateAdd("s", 1, Now) 做正确的事。并且可以概括为任意长的秒数: DateAdd("s", nSec, Now) 而不使用时间文字。要睡眠少于 1 秒,请使用 kernel32 中的 Sleep API
@ZX9 timevalue("00:00:01") = 0.0000115740... 所以 Application.wait(now + 0.00001) 大约是一秒。我喜欢用Application.wait(now + 1e-5)
秒,Application.wait(now + 0.5e-5)
半秒等等。【参考方案2】:
将此添加到您的模块中
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
或者,对于 64 位系统使用:
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
像这样在你的宏中调用它:
Sub Macro1()
'
' Macro1 Macro
'
Do
Calculate
Sleep (1000) ' delay 1 second
Loop
End Sub
【讨论】:
为什么不使用 VBA 方法而不是使用 kernel32.dll? 我使用了这种方法,因为它可以在 Access 等各种办公产品之间移植,并且不是 Excel 专用的。 我还使用了另一个 VBA 应用程序 (ERS),它具有非常有限的语言子集。 +1,因为Sleep()
允许您指定小于 1 秒的等待时间。 Application.Wait
有时过于细化。
@JulianKnight:Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
【参考方案3】:
而不是使用:
Application.Wait(Now + #0:00:01#)
我更喜欢:
Application.Wait(Now + TimeValue("00:00:01"))
因为以后读起来容易很多。
【讨论】:
它可以工作,而在 Office 2013 中,#0:0:1# 格式在午夜后转换为 1 秒。 警告:所有使用 'Application.Wait' 的解决方案都有 1 秒的误差。此方法不考虑自当前秒开始以来已经过去的毫秒数……例如,如果距离时间秒数变化仅剩 1 毫秒,则您只会休眠 1 毫秒。您只是在比较 2 个四舍五入的数字,而不是等待 1 秒!【参考方案4】:这对我来说完美无缺。在“do until”循环之前或之后插入任何代码。在您的情况下,将 5 行(time1= & time2= & "do until" 循环)放在您的 do 循环的末尾
sub whatever()
Dim time1, time2
time1 = Now
time2 = Now + TimeValue("0:00:01")
Do Until time1 >= time2
DoEvents
time1 = Now()
Loop
End sub
【讨论】:
我最喜欢这个解决方案,因为我不想停止消息队列。 这个解决方案是精确的,不需要声明 sleep-API-Function。我曾经将时间存储在 double 值中,并使用微秒来代替,结果相同。 此解决方案比下面使用Timer
的类似解决方案效果更好,因为Timer
方法在午夜前失败。
这个解决方案并不精确,它没有考虑从当前时间已经过去的毫秒数......例如,如果距离现在秒数变化仅剩 1 毫秒,您将只睡眠 1 毫秒。
当其他解决方案需要很长时间才能使用基于非 MS Office 的 VBA 宏时,这个解决方案完美运行 - 谢谢!【参考方案5】:
kernel32.dll 中的睡眠声明在 64 位 Excel 中不起作用。这会更笼统一些:
#If VBA7 Then
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If
【讨论】:
无法在 Office 2013 中编译。Office 2013 的 VBA 中的错误检查器似乎忽略了编译器语句。 在 Office 2013 中编译得很好。 大多数人都同意 Win64/VBA7 dwMilliseconds 是 Long,而不是 LongPtr。 Excel VBA 通过在外部调用后进行堆栈更正来隐藏此类错误,但此类错误会使大多数版本的 Open Office 崩溃【参考方案6】:只是 clemo 代码的清理版本 - 在 Access 中工作,它没有 Application.Wait 功能。
Public Sub Pause(sngSecs As Single)
Dim sngEnd As Single
sngEnd = Timer + sngSecs
While Timer < sngEnd
DoEvents
Wend
End Sub
Public Sub TestPause()
Pause 1
MsgBox "done"
End Sub
【讨论】:
如果Timer
给出自午夜以来的秒数,那么如果它在午夜之前执行,则此方法将失败(即,sngEnd
>= 86,400)。在午夜,Timer
重置为 0,因此永远小于 sngEnd
。
P.S.上面@clemo 的代码在一天中的任何时间都可以工作。
@vknowles,你说的完全正确。也可以通过以下方法进行补偿。由于这种方法处理毫秒,我认为这是一个安全的选择。 ``` Public Sub Sleep(sngSecs As Single) Dim sngEnd As Single sngEnd = Timer + (sngSecs / 1000) While Timer If (sngEnd - Timer) > 50000 Then sngEnd = sngEnd - 86400 End If 文末子 ```【参考方案7】:
大多数提出的解决方案都使用 Application.Wait,它不考虑自当前秒计数开始以来已经过去的时间(毫秒),因此 它们具有高达 1 秒的内在不精确度.
Timer 方法是最好的解决方案,但是你必须考虑到午夜的重置,所以这里有一个非常精确的使用 Timer 的 Sleep 方法:
'You can use integer (1 for 1 second) or single (1.5 for 1 and a half second)
Public Sub Sleep(vSeconds As Variant)
Dim t0 As Single, t1 As Single
t0 = Timer
Do
t1 = Timer
If t1 < t0 Then t1 = t1 + 86400 'Timer overflows at midnight
DoEvents 'optional, to avoid excel freeze while sleeping
Loop Until t1 - t0 >= vSeconds
End Sub
使用它来测试任何睡眠功能:(打开调试立即窗口:CTRL+G)
Sub testSleep()
t0 = Timer
Debug.Print "Time before sleep:"; t0 'Timer format is in seconds since midnight
Sleep (1.5)
Debug.Print "Time after sleep:"; Timer
Debug.Print "Slept for:"; Timer - t0; "seconds"
End Sub
【讨论】:
【参考方案8】:Application.Wait Second(Now) + 1
【讨论】:
警告:所有使用 'Application.Wait' 的解决方案都有 1 秒的误差。此方法不考虑自当前秒开始以来已经过去的毫秒数……例如,如果距离时间秒数变化仅剩 1 毫秒,则您只会休眠 1 毫秒。您只是在比较 2 个四舍五入的数字,而不是等待 1 秒!【参考方案9】:等待和睡眠功能会锁定 Excel,在延迟结束之前您无法执行任何其他操作。另一方面,循环延迟不会给你一个确切的等待时间。
所以,我做了这个解决方法,加入了这两个概念。它循环直到时间是你想要的时间。
Private Sub Waste10Sec()
target = (Now + TimeValue("0:00:10"))
Do
DoEvents 'keeps excel running other stuff
Loop Until Now >= target
End Sub
你只需要在你需要延迟的地方调用Waste10Sec
【讨论】:
【参考方案10】:Function Delay(ByVal T As Integer)
'Function can be used to introduce a delay of up to 99 seconds
'Call Function ex: Delay 2 introduces a 2 second delay before execution of code resumes
strT = Mid((100 + T), 2, 2)
strSecsDelay = "00:00:" & strT
Application.Wait (Now + TimeValue(strSecsDelay))
End Function
【讨论】:
警告:所有使用 'Application.Wait' 的解决方案都有 1 秒的误差。此方法不考虑自当前秒开始以来已经过去的毫秒数……例如,如果距离时间秒数变化仅剩 1 毫秒,则您只会休眠 1 毫秒。您只是在比较 2 个四舍五入的数字,而不是等待 1 秒!【参考方案11】:这是睡眠的替代方法:
Sub TDelay(delay As Long)
Dim n As Long
For n = 1 To delay
DoEvents
Next n
End Sub
在下面的代码中,我在旋转按钮上制作了一个“发光”效果闪烁,以便在用户“遇到问题”时将其引导到它,在循环中使用“睡眠 1000”导致没有可见的闪烁,但循环是工作得很好。
Sub SpinFocus()
Dim i As Long
For i = 1 To 3 '3 blinks
Worksheets(2).Shapes("SpinGlow").ZOrder (msoBringToFront)
TDelay (10000) 'this makes the glow stay lit longer than not, looks nice.
Worksheets(2).Shapes("SpinGlow").ZOrder (msoSendBackward)
TDelay (100)
Next i
End Sub
【讨论】:
【参考方案12】:我做了这个来回答这个问题:
Sub goTIMER(NumOfSeconds As Long) 'in (seconds) as: call gotimer (1) 'seconds
Application.Wait now + NumOfSeconds / 86400#
'Application.Wait (Now + TimeValue("0:00:05")) 'other
Application.EnableEvents = True 'EVENTS
End Sub
【讨论】:
警告:所有使用 'Application.Wait' 的解决方案都有 1 秒的误差。此方法不考虑自当前秒开始以来已经过去的毫秒数……例如,如果距离时间秒数变化仅剩 1 毫秒,则您只会休眠 1 毫秒。您只是在比较 2 个四舍五入的数字,而不是等待 1 秒!【参考方案13】:我通常使用 Timer 功能来暂停应用程序。将此代码插入您的代码
T0 = Timer
Do
Delay = Timer - T0
Loop Until Delay >= 1 'Change this value to pause time for a certain amount of seconds
【讨论】:
如果Timer
给出了从午夜开始的秒数,那么如果它在午夜之前执行,则此方法将失败(即,T0
小于从午夜开始的延迟秒数) .在午夜,Timer
在达到延迟限制之前重置为 0。 Delay
永远不会达到延迟限制,所以循环永远运行。
由于 Timer 产生非整数值,你应该使用Loop Until Delay >= 1
,否则你可能会超过 1 并且永远不会退出循环。【参考方案14】:
试试这个:
Threading.thread.sleep(1000)
【讨论】:
【参考方案15】:你可以使用 Application.wait now + timevalue("00:00:01") 要么 Application.wait now + timeserial(0,0,1)
【讨论】:
以上是关于如何暂停特定的时间? (Excel/VBA)的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Excel VBA 打开 Outlook excel 附件,在特定时间范围内发送到特定 Outlook 文件夹?
当另一个框在excel(VBA)中具有特定值时,如何引用msgBox中的单元格。