如何暂停特定的时间?(Excel / VBA)


103

我有一个包含以下宏的Excel工作表。我想每秒钟循环一次,但如果我能找到执行此操作的功能,就会感到惊讶。有可能吗

Sub Macro1()
'
' Macro1 Macro
'
Do
    Calculate
    'Here I want to wait for one second

Loop
End Sub

Answers:


128

使用Wait方法

Application.Wait Now + #0:00:01#

或(对于Excel 2010及更高版本):

Application.Wait Now + #12:00:01 AM#

我不确定您的意思是什么,但我推测您想要DoEvents按此处的演示dailydoseofexcel.com/archives/2005/06/14/stopwatch
Ryan Shannon

3
@Benoit和@Keng,您可以直接输入1秒,避免将文本转换为日期。对我来说更干净: Application.Wait(Now + #0:00:01#)干杯!
A.Sommerh 2014年

29
该格式在Excel 2010中不起作用。但是可以使用:Application.Wait (Now + TimeValue("0:00:01"))
ZX9 2015年

1
DateAdd(“ s”,1,Now)做正确的事情。可以在很长的几秒钟内进行概括:DateAdd(“ s”,nSec,Now),而无需使用时间文字。要睡眠少于1秒,请使用kernel32中的Sleep API
Andrew Dennison

1
@ ZX9 timevalue(“ 00:00:01”)= 0.0000115740 ...因此Application.wait(现在+ 0.00001)大约是一秒钟。我喜欢用Application.wait(now + 1e-5)一秒钟,Application.wait(now + 0.5e-5)半秒钟等等
。– Some_Guy

61

将此添加到您的模块

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

1
为什么不使用VBA方法而不是使用kernel32.dll呢?
本S

10
我已经使用了这种方法,因为它可以在Access等各种办公产品之间移植,并且不是Excel专用的。
布格比尔

我还使用了另一个VBA应用程序(ERS),该应用程序的语言子集非常有限。
布格比尔

18
+1,因为Sleep()您可以指定少于1秒的等待时间。Application.Wait有时过于精细。
BradC

2
@JulianKnight:Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
Vegard

42

而不是使用:

Application.Wait(Now + #0:00:01#)

我更喜欢:

Application.Wait(Now + TimeValue("00:00:01"))

因为此后更容易阅读。


7
它可以正常工作,而在Office 2013中,#0:0:1#格式在午夜之后转换为1秒。
朱利安·奈特

1
警告:所有使用“ Application.Wait”的解决方案都有1秒的不精确性。此方法不考虑自当前秒开始以来已经过去的毫秒。例如,如果距离时间仅剩1毫秒,那么您将仅睡眠1毫秒。您只是比较2个舍入的数字,而不是等待1秒!
cyberponk

18

这对我来说完美无缺。在“直到”循环之前或之后插入任何代码。在您的情况下,请将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

2
我最喜欢此解决方案,因为我不想停止消息队列。
Daniel Fuchs 2015年

此解决方案是精确的,不需要声明sleep-API-Function。我曾经将时间存储为双精度值,而是使用微秒来获得相同的结果。
DrMarbuse

该解决方案比下面使用的类似解决方案更好,Timer因为该Timer方法在午夜之前失效。
vknowles

1
该解决方案并不精确,它没有考虑到从当前时间开始已经经过的毫秒数。例如,如果距离Now秒仅剩1毫秒,则您只会休眠1毫秒。
cyberponk

当其他解决方案对于基于非MS Office的VBA宏需要花费很长时间时,该解决方案效果很好-谢谢!
好奇的

12

kernel32.dll中的Sleep声明在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

2
无法在Office 2013中进行编译。Office 2013的VBA中的错误检查器似乎忽略了编译器语句。
朱利安·奈特

2
编译罚款,我在办公室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

2
如果Timer给出自午夜以来的秒数,则该方法在午夜之前执行(即,sngEnd> = 86,400)失败。午夜时分,Timer重置为0,因此比sngEnd永远少。
vknowles

PS上面@clemo中的代码在一天中的任何时间都有效。
vknowles

@vknowles,您说的是绝对正确的。并且也可以通过以下方法进行补偿。由于此方法可以处理毫秒,因此我认为这是一个安全的选择。```Public Sub Sleep(sngSecs as Single)Dim sngEnd as Single sngEnd = Timer +(sngSecs / 1000)While Timer <sngEnd DoEvents If(sngEnd-Timer)> 50000然后sngEnd = sngEnd-86400 End如果 Wend End Sub`` `
PravyNandas

5

所介绍的大多数解决方案都使用Application.Wait,它没有考虑自从秒数开始计数以来已经经过的时间(毫秒),因此它们的固有误差高达1秒

计时器方法是最好的解决方案,但是您必须考虑在午夜进行重置,因此这是使用计时器的非常精确的睡眠方法:

'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

3

Application.Wait Second(Now) + 1


警告:所有使用“ Application.Wait”的解决方案都有1秒的不精确性。此方法不考虑自当前秒开始以来已经过去的毫秒。例如,如果距离时间仅剩1毫秒,那么您将仅睡眠1毫秒。您只是比较2个舍入的数字,而不是等待1秒!
cyberponk

2
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

1
警告:所有使用“ Application.Wait”的解决方案都有1秒的不精确性。此方法不考虑自当前秒开始以来已经过去的毫秒。例如,如果距离时间仅剩1毫秒,那么您将仅睡眠1毫秒。您只是比较2个舍入的数字,而不是等待1秒!
cyberponk

2

这是睡眠的替代方法:

Sub TDelay(delay As Long)
Dim n As Long
For n = 1 To delay
DoEvents
Next n
End Sub

在下面的代码中,我使旋转按钮上的“发光”效果闪烁,以指示用户是否遇到“麻烦”,在循环中使用“ sleep 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

1

我这样做是为了回答问题:

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秒!
cyberponk

1

我通常使用Timer函数暂停应用程序。将此代码插入您的代码中

T0 = Timer
Do
    Delay = Timer - T0
Loop Until Delay >= 1 'Change this value to pause time for a certain amount of seconds

3
如果TimerT0出自午夜以来的秒数,则该方法在午夜之前执行(即,该时间少于自午夜起的延迟秒数)将失败。在午夜,Timer在达到延迟限制之前重置为0。Delay永远不会达到延迟限制,因此循环永远运行。
vknowles

由于Timer会产生非整数值,因此您应该使用Loop Until Delay >= 1,否则就有可能超过1并且永远不会退出循环。
乔恩·

1

等待和睡眠功能会锁定Excel,直到延迟结束,您才能执行其他任何操作。另一方面,循环延迟不会给您确切的等待时间。

因此,我将这种解决方法加入了两个概念。循环播放直到您需要的时间为止。

Private Sub Waste10Sec()
   target = (Now + TimeValue("0:00:10"))
   Do
       DoEvents 'keeps excel running other stuff
   Loop Until Now >= target
End Sub

您只需要在需要延迟的地方致电Waste10Sec



0

您可以使用Application.wait now + timevalue(“ 00:00:01”)或Application.wait now + timeserial(0,0,1)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.