VBA的Sleep函数无效

21

我知道我在这里做错了什么。我试着使用sleep函数来延迟我的代码,但是我收到了"Sub或Function未定义"的错误提示。有什么建议吗?

7个回答

27

VBA没有Sleep函数。

你可以像这样从Kernel32.dll导入它:

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
请注意,这将冻结应用程序。
您还可以在While循环中调用DoEvents,这不会冻结应用程序。

尽管存在应用程序挂起的问题,但我仍然更喜欢这种方法,因为循环方法会使用太多CPU。 - KalenGi
@kalengi:你应该使用异步操作。 - SLaks
@SLaks 异步与 Sleep,你是什么意思? - KalenGi
@kalengi:理想情况下,使用Await Task.Delay()。在VBA中,我不知道是否有任何适当的方法来实现它。 - SLaks
这个解决方案在64位Windows应用程序或Mac上不起作用。在while循环中使用DoEvents会导致过多的CPU使用率。请查看此解决方案,它解决了所有这些问题。 - GWD
显示剩余2条评论

19

我尝试的所有方法似乎都会让应用程序停止响应,包括使用Application.Wait。不过,以下这种方式似乎可行:

waitTill = Now() + TimeValue("00:15:00")

While Now() < waitTill
    DoEvents
Wend

1
我喜欢这个程序,它运行得很好,只有一个例外。我找不到一种方法来设置500毫秒的等待时间...所以1秒是最小等待时间。有没有办法做到少于1秒? - BobNoobGuy
如果您需要更高的分辨率,可以在kernel32.dll中使用GetSystemTime:http://www.freevbcode.com/ShowCode.asp?ID=1618 或者如果在Excel中,您可以调用电子表格now()函数(作为VBA中的[now()]),该函数也具有更高的分辨率:https://groups.google.com/forum/#!topic/microsoft.public.excel.programming/-D6lkjJv2ew - Anthony Hayward
1
在Excel中,您可以在调用Now函数时使用方括号来获取具有亚秒精度的工作表函数版本。 [Now()] - HackSlash
2
其中一种更优雅的解决方案 :) - Newteq Developer
这不是一个好的解决方案,它会导致高 CPU 使用率(1 个线程获得最大使用率),并且不能提供小于 1 秒的分辨率。请使用此解决方案,它可以解决这两个问题。 - GWD

7

4
这仅适用于“Excel.Application”。其他Office应用程序对象模型不存在“Wait”方法。 - C Perkins

4
Application.Wait DateAdd("m", 10, Now) ' Wait for 10 Minutes
 Application.Wait DateAdd("s", 10, Now) ' wait for 10 seconds

2
欢迎来到Stack Overflow!感谢您发布答案!请务必仔细阅读有关自我推广的FAQ。同时请注意,每次链接到您自己的网站/产品时,必须发布免责声明。 - Andrew Barber
@AndrewBarber:看了一下链接,它似乎不是Babu的网站,而更像是SO的一个有用的阅读材料。你为什么想要删除它呢? - Peter Albert
@PeterAlbert 这是Babu的网站。最近他们一直在垃圾邮件攻击(因为他们的多个答案被删除,因为它们甚至没有包含这么多信息),并且这在他们的个人资料中也有体现。 - Andrew Barber
1
@AndrewBarber - 感谢您提供的信息!我必须承认,我本不会注意到! - Peter Albert
如果您想表示分钟,请使用“n”。 "m" 表示月份。 - MatAff

2

暂停应用程序10秒钟:

Application.Wait (Now + TimeValue("0:00:10"))

你好,你能想到为什么这个函数在MS Outlook中不可用吗?由于某种原因,Alt+F11 VBA编辑器似乎没有显示它,并且当我在Outlook邮件的函数中运行它时它也无法工作(从规则中)。谢谢! - Kalin
@Kalin 看看这个跨平台、跨应用的解决方案(https://dev59.com/kXI_5IYBdhLWcg3wEOrq#74387976),它不会冻结应用程序,也不会导致过多的CPU使用。 - GWD

2

使用这段代码可以避免Excel冻结并且CPU使用率低:

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub Delay(s As Single)
    Dim TimeOut As Single
    TimeOut = Timer + s
    Do While Timer < TimeOut
        DoEvents
        Sleep 1 'With this line the CPU usage is 00 instead of 50 with an absolute error of +1ms and the latency of 1ms.
    Loop
End Sub

这个解决方案有一个严重的 bug:当 Timer + s > 86400 时,如果在午夜前不久调用,它将永远不会停止睡眠!此外,这个解决方案在 Mac 或 64 位 Windows 应用程序中无法工作。要解决这两个问题,请查看这里。另外,请注意 Sleep 的时间分辨率实际上不是1毫秒 - GWD

1
以下是在32位和64位Windows机器上实现交叉兼容所需的内容。 延迟以毫秒为单位,因此使用1000表示1秒延迟。
首先,在模块中将此代码放在其他Subs / Functions之前。 在64位计算机上,“#Else”后面的行将会突出显示,但这不是问题。 代码将编译并运行。
#If VBA7 Then
    Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else
    Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If

现在你可以像这个例子一样创建一个1.5秒的延迟:
Sub ExampleWithDelay()
    Msgbox "This is a message before the delay."
    Sleep 1500    ' delay of 1,000 milliseconds or 1.5 seconds
    Msgbox "This is a message -AFTER- the delay."
End Sub

正如@SLaks所指出的那样,这会冻结应用程序(防止用户输入),但您也可以在While循环中调用DoEvents。请参见下面的示例。它运行10秒并允许用户交互。

每1/10秒,它会更新Excel状态栏,显示:

  1. The address of the active cell

  2. A countdown

    Sub ExampleWithDelayInLoop()    ' for MS Excel
    
        Dim thisMessage As String
        Dim countdownText As String
        Dim i As Long
    
        Const TOTAL_SECONDS As Byte = 10
    
        For i = 1 To TOTAL_SECONDS * 10
    
            countdownText = Excel.WorksheetFunction.RoundUp(TOTAL_SECONDS - (i / 10), 0)
            thisMessage = "You selected " & Excel.ActiveCell.Address & Space$(4) & countdownText & " seconds remaining"
    
            ' Show the address of the active cell and a countdown in the Excel status\
            '   bar.
            If Not Excel.Application.StatusBar = thisMessage Then
                Excel.Application.StatusBar = thisMessage
            End If
    
            ' Delay 1/10th of a second.
            '   Input is allowed in 1/10th second intervals.
            Sleep 100
            DoEvents
    
        Next i
    
    
        ' Reset the status bar.
        Excel.Application.StatusBar = False
    End Sub
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接