在Access VBA中,是否有与Thread.Sleep()
相当的功能?
Declare Sub Sleep Lib "kernel32" Alias "Sleep" _
(ByVal dwMilliseconds As Long)
使用以下语法调用Sleep函数:Sub Sleep()
Sleep 1000 'Implements a 1 second delay
End Sub
不使用 kernel32 的另一种方法:
Dim started As Single: started = Timer
Do: DoEvents: Loop Until Timer - started >= 1
Sub Wait(seconds As Integer)
Dim now As Long
now = Timer()
Do
DoEvents
Loop While (Timer < now + seconds)
End Sub
需要进行一些修改才能使代码正常工作。以下是已经修正的代码。
Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
Sub SleepVBA()
Sleep 1000 'Implements a 1 second delay
End Sub
我在Excel中使用这个功能,效果非常好:
Application.Wait DateAdd("s", 1, Now())
DateAdd() 是一个函数,它基于 Now()
(在这种情况下 - 您可以使用其他值作为参数)设置时间,"s"
是时间度量(在本例中为秒),并增量为 1。因此,在这里,函数调用告诉应用程序等待 1 秒。
被接受的答案在64位VBA中无法使用。此外,它无法在Mac上工作。
感谢@Cristian Buse在您的评论中指出Mac的兼容性!
实现完全的Mac兼容性需要导入特定于平台的库函数以挂起线程执行,即Mac上为usleep
,Windows上为Sleep
。由于usleep
将其参数以微秒为单位传递,而Sleep
使用毫秒,因此需要声明一个自定义的Sub
来处理转换。
导入库函数并声明Sub
可以按以下方式完成。
这个解决方案是我和Cristian Buse共同合作改编他的原始方案而来,以避免整数溢出并允许在 Mac 上使用超过&HFFFFFFFF
微秒(约71分钟)的Sleep
时间:
#If Mac Then
#If VBA7 Then
Private Declare PtrSafe Sub USleep Lib "/usr/lib/libc.dylib" Alias "usleep" (ByVal dwMicroseconds As Long)
#Else
Private Declare Sub USleep Lib "/usr/lib/libc.dylib" Alias "usleep" (ByVal dwMicroseconds As Long)
#End If
#Else
#If VBA7 Then
Private Declare PtrSafe Sub MSleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
#Else
Private Declare Sub MSleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
#End If
#End If
'Sub providing a Sleep API consistent with Windows on Mac (argument in ms)
'Authors: Guido Witt-Dörring, https://dev59.com/L3RB5IYBdhLWcg3w6bYE#74262120
' Cristian Buse, https://dev59.com/9sLra4cB1Zd3GeqPBhQO#71176040
Public Sub Sleep(ByVal dwMilliseconds As Long)
#If Mac Then 'To avoid overflow issues for inputs > &HFFFFFFFF / 1000:
Do While dwMilliseconds And &H80000000
USleep &HFFFFFED8
If dwMilliseconds < (&H418937 Or &H80000000) Then
dwMilliseconds = &H7FBE76C9 + (dwMilliseconds - &H80000000)
Else: dwMilliseconds = dwMilliseconds - &H418937: End If
Loop
Do While dwMilliseconds > &H418937
USleep &HFFFFFED8: dwMilliseconds = dwMilliseconds - &H418937
Loop
If dwMilliseconds > &H20C49B Then
USleep (dwMilliseconds * 500& Or &H80000000) * 2&
Else: USleep dwMilliseconds * 1000&: End If
#Else 'Windows
MSleep dwMilliseconds
#End If
End Sub
现在 Sleep
将在 Windows 和 Mac 上以及在 32 位和 64 位环境中都可用。
可以这样调用:
Sub ExampleSleepCall()
Sleep 1000 'Suspends thread execution for 1 second
'Calling application will freeze completely for that amount of time!
'If this is undesired, look here: https://dev59.com/kXI_5IYBdhLWcg3wEOrq#74387976
End Sub
请注意:
Sleep
函数虽然以毫秒为单位接受参数,但其分辨率实际上不是1毫秒。usleep
持续时间受到 MAX_UINT = &HFFFFFFFF
微秒或约 4294.97 秒(~71 分钟)的限制。这就是为什么 Mac 上的自定义 Sleep
子程序会对输入值 dwMilliseconds > &H418937
调用多次 usleep
,以避免整数溢出问题。Sleep
子程序的 Mac 上),最大的 Sleep
持续时间受到 MAX_UINT
毫秒或约 4294967.3 秒(~49.71 天)的限制。MAX_LONG = &H7FFFFFFF
(= 2147483647
)的毫秒值需要传递负的 VBA Long
值,通过像这样调用它来实现最大的 Sleep 持续时间:Sleep -1
(=Sleep &HFFFFFFFF
)最重要的是,所有 Microsoft Office 应用程序都在与主用户界面相同的线程中运行 VBA 代码。这意味着,调用 Sleep
实际上会冻结整个应用程序(在任务管理器中将显示为“未响应”)。除非等待时间过去或强制退出应用程序并重新启动它,否则没有办法从此状态恢复。Excel 的 Application.Wait
也存在同样的问题。虽然在这种情况下应用程序不会在任务管理器中显示为 not responding
,但对于用户来说,它仍然无响应。
解决此问题的方法是在循环中调用 DoEvents
,正如其他人已经指出的那样。然而,这又带来了另一个问题。因为应用程序将尝试尽可能快地执行 VBA 代码,所以 DoEvents 以最大可达速率调用,从而完全占用单个线程上的 CPU,导致高,不必要的 CPU 和电源使用,并潜在地减慢 UI 中的其他更重要任务。
要了解暂停VBA执行的最佳方法,请查看此答案。
可以从Access VBA使用Excel的Wait()过程。
第一步是确保在项目中引用了Excel库。
完成后,以下代码将等待十秒钟:
Call Excel.Application.Wait(Time:=DateAdd("s",10,Now()))
添加
Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
一些代码问题在其他地方引起了一些额外的问题。 最终我使用了在另一个论坛上找到并稍作调整的这个函数:
Function WaitTime(n As Double)
'Function that wait an amount of time n in seconds
TWait = Time
TWait = DateAdd("s", n, TWait)
Do Until TNow >= TWait
TNow = Time
Loop
End Function
如果代码正在表单中执行,您可以使用表单的内置计时器。
使用以下代码启动表单的计时器:
TimerInterval = 1000 ' Delay in ms
声明一个事件处理程序:
Private Sub Form_Timer()
TimerInterval = 0 ' Stop the timer if don't want to repeat the event each second
' Execute your code here
End Sub