如何在VBA中调节功能?
我正在使用组合框和VBA在Excel内部进行下拉。我已经能够让它向远程api发出请求,将返回的数据添加到隐藏的工作表中,并根据api的结果更新下拉选项 我要做的是限制api请求。目前,如果Excel已经在处理api请求,它似乎不会启动sub。这并不理想,因为人们通常会连续快速键入多个字符。我想为每个子调用添加一个计时器,如果在~250ms内没有新的子函数调用,则发送api请求。如果在250ms内再次调用,我想取消该sub的执行 最初,我尝试创建一个全局“process_id”,子进程将向当前全局添加1,将其本地id设置为该值,等待x时间,检查其本地id==全局id,如果不退出子进程,则退出子进程。但是,现在似乎第二个子进程在计时器等待x时间时从不运行,因此第一个子进程仍然运行,仅仅过了x秒(第二个潜艇根本就没有运行过)如何在VBA中调节功能?,vba,excel,Vba,Excel,我正在使用组合框和VBA在Excel内部进行下拉。我已经能够让它向远程api发出请求,将返回的数据添加到隐藏的工作表中,并根据api的结果更新下拉选项 我要做的是限制api请求。目前,如果Excel已经在处理api请求,它似乎不会启动sub。这并不理想,因为人们通常会连续快速键入多个字符。我想为每个子调用添加一个计时器,如果在~250ms内没有新的子函数调用,则发送api请求。如果在250ms内再次调用,我想取消该sub的执行 最初,我尝试创建一个全局“process_id”,子进程将向当前全局
如何在Excel VBA中限制子函数,以便在第一个子函数等待时可以运行相同的子函数?按照您使用全局变量的方法,保留一个来跟踪
计时器
函数。不幸的是,您没有提供代码,所以我只能假设您应该如何实现它
Private myTimer As Single '// Global Variable, outside of any routine
Sub foo()
If Timer - myTimer < 0.25 Then Exit Sub
callMyAPI
myTimer = Timer
End Sub
在每次API调用中,您将重置
myTimer
变量。如前所述;您需要一个毫秒精度的异步计时器
希望以下内容对您有用:
设置计时器时,不应再设置其他计时器,并且当计时器触发事件时,计时器会自行停止,因此在“DelayTimeSeconds”期间的多个调用只会导致对API的一个调用
我认为您真正想要的是“在我停止键入之前不要调用API”(即,在上一次键入的x毫秒内没有进一步的按键)
如果这就是你想要的,那么这个(帽子尖指向@Tragamor的答案)应该可以做到。这与使用window.setTimeout
在js中所做的工作非常接近
在常规代码模块中:
Option Explicit
Public Declare Function SetTimer Lib "user32" ( _
ByVal HWnd As Long, ByVal nIDEvent As Long, _
ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public Declare Function KillTimer Lib "user32" ( _
ByVal HWnd As Long, ByVal nIDEvent As Long) As Long
Private TimerID As Long
'this function called from the control's Change event
Function CallApi()
Const DelayMsec As Long = 500
If TimerID > 0 Then KillTimer 0&, TimerID 'kill any existing timer
TimerID = SetTimer(0&, 0&, DelayMsec, AddressOf CallApi2) 'set a timer
End Function
'this function called from the timer
Sub CallApi2()
If TimerID > 0 Then KillTimer 0&, TimerID
Debug.Print "Calling API with '" & Sheet1.TextBox1.Text & "'"
End Sub
我不确定您是否可以在VBA中设置异步计时器,这正是您在这里需要的。VBA中通常使用的计时器或多或少都是阻塞的,除了OnTime,但它的最小分辨率为1秒…PS:显然,世界上最快的键入wpm大约为215,因此大约0.4s的延迟时间可能是一个可接受的值
' Adapted from https://groups.google.com/forum/?hl=en#!topic/microsoft.public.excel.programming/Ce--7sympZM
' These procedures require that you are using Office 2000 or later, because of the AddressOf function
Public Declare Function SetTimer Lib "user32" ( _
ByVal HWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public Declare Function KillTimer Lib "user32" ( _
ByVal HWnd As Long, ByVal nIDEvent As Long) As Long
Private AllowFireTime As Single
Private TimerID As Long
Private TimerSeconds As Single
Private TimerSet As Boolean
Const DelayTimeSeconds As Single = 0.75
Sub TestFireDelay()
CallAPIProc
End Sub
Private Function CallAPIProc()
Dim NowTime As Single: NowTime = Timer
If AllowFireTime > NowTime Then
If TimerSet = False Then StartTimer AllowFireTime - NowTime
Else
AllowFireTime = NowTime + DelayTimeSeconds
Call TestCall
' Code for API Call
End If
End Function
Function StartTimer(Optional TimerSeconds = 1) ' how often to "pop" the timer.
TimerID = SetTimer(0&, 0&, TimerSeconds * 1000&, AddressOf TimerProc)
TimerSet = True
End Function
Function EndTimer()
On Error Resume Next
KillTimer 0&, TimerID
TimerSet = False
End Function
Function TimerProc(ByVal HWnd As Long, ByVal uMsg As Long, ByVal nIDEvent As Long, ByVal dwTimer As Long)
' The procedure is called by Windows. Put your timer-related code here.
'
Call EndTimer
Call CallAPIProc
End Function
Function TestCall()
Debug.Print Format(Now, "hh:mm:ss") & "." & Strings.Right(Strings.Format(Timer, "#0.00"), 2)
End Function
Option Explicit
Public Declare Function SetTimer Lib "user32" ( _
ByVal HWnd As Long, ByVal nIDEvent As Long, _
ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public Declare Function KillTimer Lib "user32" ( _
ByVal HWnd As Long, ByVal nIDEvent As Long) As Long
Private TimerID As Long
'this function called from the control's Change event
Function CallApi()
Const DelayMsec As Long = 500
If TimerID > 0 Then KillTimer 0&, TimerID 'kill any existing timer
TimerID = SetTimer(0&, 0&, DelayMsec, AddressOf CallApi2) 'set a timer
End Function
'this function called from the timer
Sub CallApi2()
If TimerID > 0 Then KillTimer 0&, TimerID
Debug.Print "Calling API with '" & Sheet1.TextBox1.Text & "'"
End Sub