如何在excel VBA中检查或取消多个挂起的application.ontime事件?

hpxqektj  于 2023-05-08  发布在  其他
关注(0)|答案(5)|浏览(333)

我正在使用Application.Ontime事件从单元格中提取时间字段,并计划在该时间运行一个子例程。MyApplication.Ontime事件在Workbook_BeforeSave事件上运行。因此,如果用户**(更改所需时间+保存工作簿)**多次,则会创建多个Application.Ontime事件。从理论上讲,我可以用一个唯一的时间变量来跟踪每个事件。但是有没有一种方法可以检查/解析/取消未决事件呢?

Private Sub Workbook_BeforeSave
    SendTime = Sheets("Email").Range("B9")
    Application.OnTime SendTime, "SendEmail"
End Sub

Private Sub Workbook_BeforeClose
    Application.OnTime SendTime, "SendEmail", , False
End Sub

因此,如果我:
将B 9更改为12:01,保存工作簿
将B 9更改为12:03,保存工作簿
将B 9更改为12:05,保存工作簿
将B 9更改为12:07,保存工作簿
等等
我最终会触发多个事件。我只想激发一个事件(最近安排的事件)
如何取消Workbook_BeforeClose事件上的所有挂起事件(或至少枚举它们)?

hof1towb

hof1towb1#

我不认为你可以遍历所有的未决事件,或者在一个shabang中取消它们。我建议设置一个模块级别或全局布尔值来指示是否触发事件。所以你会得到这样的结果:

Dim m_AllowSendMailEvent As Boolean
Sub SendMail()
If Not m_AllowSendMailEvent Then Exit Sub

'fire event here

End Sub

编辑:

将其添加到工作表模块的顶部,其中包含包含您所需的日期/时间值的范围:

' Most recently scheduled OnTime event. (Module level variable.)
Dim PendingEventDate As Date

' Indicates whether an event has been set. (Module level variable.)
Dim EventSet As Boolean

Private Sub Worksheet_Change(ByVal Target As Range)

Dim SendTimeRange As Range

' Change to your range.
Set SendTimeRange = Me.Range("B9")

' If the range that was changed is the same as that which holds
' your date/time field, schedule an OnTime event.
If Target = SendTimeRange Then

    ' If an event has previously been set AND that time has not yet been
    ' reached, cancel it. (OnTime will fail if the EarliestTime parameter has
    ' already elapsed.)
    If EventSet And Now > PendingEventDate Then

        ' Cancel the event.
        Application.OnTime PendingEventDate, "SendEmail", , False

    End If

    ' Store the new scheduled OnTime event.
    PendingEventDate = SendTimeRange.Value

    ' Set the new event.
    Application.OnTime PendingEventDate, "SendEmail"

    ' Indicate that an event has been set.
    EventSet = True

End If

End Sub

这是一个标准模块:

Sub SendEmail()

    'add your proc here

End Sub
osh3o9ms

osh3o9ms2#

每次调用Application.Ontime时,保存事件设置为运行的时间(可以将其保存在工作表或模块作用域的动态数组中)
每次触发事件时,请删除相应的已保存时间
要取消所有挂起的事件,请在schedule = false的情况下调用Application.Ontime,遍历剩余的已保存时间

gr8qqesn

gr8qqesn3#

我想我可能有一个有效的解决方案,基于已经给出的一些建议。
简而言之,我们创建了一个全局数组,每次用户点击save时,SendTime都会写入该数组。这有助于跟踪我们所有的计划时间。
当工作簿关闭时,我们循环遍历数组并删除所有计划的时间。
我测试了这个,它似乎在Excel 2003上工作。让我知道你进展如何。

Dim scheduleArray() As String //Set as global array to hold times

Private Sub Workbook_BeforeSave
    SendTime = Sheets("Email").Range("B9")
    AddToScheduleArray SendTime
    Application.OnTime SendTime, "SendEmail"
End Sub

Private Sub Workbook_BeforeClose
    On Error Resume Next
    Dim iArr As Integer, startTime As String

    For iArr = 0 To UBound(scheduleArray) - 1 //Loop through array and delete any existing scheduled actions 
        startTime = scheduleArray(iArr)
        Application.OnTime TimeValue(startTime), "SendEmail", , False
    Next iArr
End Sub

Sub AddToScheduleArray(startTime As String)
    Dim arrLength As Integer

    If Len(Join(scheduleArray)) < 1 Then
        arrLength = 0
    Else
        arrLength = UBound(scheduleArray)
    End If

    ReDim Preserve scheduleArray(arrLength + 1) //Resize array
    scheduleArray(arrLength) = startTime //Add start time
End Sub
kmb7vmvb

kmb7vmvb4#

或者你可以创建一些单元格(如abacus),例如:
如果使用application.ontime:

if range("V1") < 1 then

    Application.OnTime dTime, "MyMacro"

    range("V1")=range("V1") + 1

 end if

如果我不想数的话

Application.OnTime dTime, "MyMacro", , False

   range("V1")=range("V1") - 1
g6ll5ycj

g6ll5ycj5#

我不知道我是否错过了什么,但为什么不在开始新的呼叫之前取消一个呼叫呢?

Private Sub Workbook_BeforeSave
    On Error Resume Next 'this is here for the first call when there is nothing yet to cancel
    Application.OnTime SendTime, "SendEmail", , False
    SendTime = Sheets("Email").Range("B9")
    Application.OnTime SendTime, "SendEmail"
End Sub

Private Sub Workbook_BeforeClose
    Application.OnTime SendTime, "SendEmail", , False
End Sub
  • 假设SendTime是全局变量

这会导致在任何给定时间只运行一个Call--如果我对这个问题的理解是正确的,那就是期望的行为。

相关问题