如何暂停特定的时间? (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 &gt;= 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中的单元格。

Excel,VBA中,如何判断变量是不是包含特定字符串

如何使用 Excel VBA 将特定行从多个工作表复制到另一个工作表?

返回数组Excel VBA中元素的索引

如何使用Excel VBA仅更新特定工作表中的链接,而不是整个工作簿?