【问题标题】:How to pause for specific amount of time? (Excel/VBA)如何暂停特定的时间? (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

【问题讨论】:

    标签: excel vba


    【解决方案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)

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-02-24
              • 2017-09-25
              • 2015-10-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-12-10
              相关资源
              最近更新 更多