Excel VBA多个Application.OnTime

时间:2014-05-27 07:28:07

标签: excel vba excel-vba

我正在尝试在sub中使用多个Application.OnTime,我得到了意想不到的结果。

这就是我想要做的事情:

  1. 使用"递归"每隔1分钟运行一个sub(testOnTime)调用

    内部子(testOnTime):

    1. run" firstSection"进入sub(testOnTime)后10秒

      Inside" firstSection":将调试消息写入Excel工作表" MySheet"

    2. run" lastSection"进入sub(testOnTime)后40秒

      Inside" lastSection":将调试消息写入Excel工作表" MySheet"

    3. 将调试信息写入Excel工作表" Mysheet"

    4. 有sub" testOnTime"跑5次?:不 - >继续,是 - >出口

  2. 代码:

    Option Explicit
    
    Public rowCnt As Integer
    Public Cnt As Integer
    Public Const sheetName = "MySheet"
    Public Const inc1 = "00:00:40"
    Public Const inc2 = "00:00:10"
    Public timeStr1 As Date
    Public timeStr2 As Date
    Public timeStr3 As Date
    
    Public Sub MyMain()
    
         rowCnt = 1
         Cnt = 0
    
         Call testOnTime
    
         Worksheets(sheetName).Range("A" & CStr(rowCnt)).Value = "Done"
    
    End Sub
    
    Public Sub testOnTime()
    
    
         ' wait-time for last section
         timeStr1 = Format(Now + TimeValue(inc1), "hh:mm:ss")
         ' wait time for first section
         timeStr2 = Format(Now + TimeValue(inc2), "hh:mm:ss")
         ' wait for 1 minute
         timeStr3 = Format(Now + TimeValue("00:01:00"), "hh:mm:ss")
    
    
         ' wait utill 10 seconds
         Application.OnTime TimeValue(timeStr2), "firstSection"
    
         ' wait utill 40 seconds
         Application.OnTime TimeValue(timeStr1), "lastSection"
    
         ' debug msgs
         Worksheets(sheetName).Range("A" & CStr(rowCnt)).Value = "Outside @ " & CStr(timeStr3)
         Worksheets(sheetName).Range("B" & CStr(rowCnt)).Value = CStr(rowCnt)
         Worksheets(sheetName).Range("C" & CStr(rowCnt)).Value = CStr(Cnt)
         rowCnt = rowCnt + 1
    
         Cnt = Cnt + 1
    
        If Cnt < 5 Then
             ' wait until Now + 1 min
             Application.OnTime TimeValue(timeStr3), "testOnTime"
        End If
    
    End Sub
    
    Public Sub firstSection()
        ' debug msgs for first section
        Worksheets(sheetName).Range("A" & CStr(rowCnt)).Value = "In first section @ " & CStr(timeStr2)
        Worksheets(sheetName).Range("B" & CStr(rowCnt)).Value = CStr(rowCnt)
        Worksheets(sheetName).Range("C" & CStr(rowCnt)).Value = CStr(Cnt)
        rowCnt = rowCnt + 1
    End Sub
    
    Public Sub lastSection()
        ' debug msgs for first section
        Worksheets(sheetName).Range("A" & CStr(rowCnt)).Value = "In last section @ " & CStr(timeStr1)
        Worksheets(sheetName).Range("B" & CStr(rowCnt)).Value = CStr(rowCnt)
        Worksheets(sheetName).Range("C" & CStr(rowCnt)).Value = CStr(Cnt)
        rowCnt = rowCnt + 1
    End Sub
    

    Current output

    1. 为什么&#34;外面......&#34;首先写入excel表,当它应该是宏内的最后一条指令时?

    2. 为什么宏输出&#34; 2&#34;应该只输出一次的同一件事的消息?

    3. 有没有更好的方法来实现我想要的目标而不使用&#34; OnTime&#34;?

2 个答案:

答案 0 :(得分:2)

我运行了代码,我觉得它运行正常 - 我必须承认我对它的目标有点困惑。我没有看到任何加倍的消息。

我能够通过运行两次宏来设计加倍的消息 - excel很高兴让它运行两次,然后你会得到一倍的消息。这是什么导致了这个问题?

我认为你误解了Application.OnTime是如何运行的 - 它是一个非阻塞调用,因此它创建了对指定子例程的未来调用,然后继续 - 这就是&#34; outside&#34;消息首先显示。我认为这也是&#34; Done&#34;消息会立即显示,直到它被覆盖。

希望这有帮助

答案 1 :(得分:0)

我认为我找到了实现我想要实现的目标的方法,下面是代码

更新代码:

Option Explicit

Public rowCnt As Integer
Public Cnt As Integer
Public Const sheetName = "MySheet"
Public Const inc1 = "00:00:40"
Public Const inc2 = "00:00:10"
Public timeStr1 As Date
Public timeStr2 As Date
Public timeStr3 As Date
Public firstFlag As Boolean
Public lastFlag As Boolean


Public Sub MyMain()

    rowCnt = 1
    Cnt = 0

    Call testOnTime

    Worksheets(sheetName).Range("A" & CStr(rowCnt)).Value = "Done"

End Sub

Public Sub testOnTime()

    ' wait-time for last section
    timeStr1 = Format(Now + TimeValue(inc1), "hh:mm:ss")
    ' wait time for first section
    timeStr2 = Format(Now + TimeValue(inc2), "hh:mm:ss")
    ' wait for 1 minute
    timeStr3 = Format(Now + TimeValue("00:01:00"), "hh:mm:ss")


    ' wait utill 10 seconds
    firstFlag = False
    Application.OnTime TimeValue(timeStr2), "firstSection"
    While Not firstFlag
        DoEvents
    Wend


    ' wait utill 40 seconds
    lastFlag = False
    Application.OnTime TimeValue(timeStr1), "lastSection"
    While Not lastFlag
        DoEvents
    Wend

    ' debug msgs
    Worksheets(sheetName).Range("A" & CStr(rowCnt)).Value = "Outside @ " & CStr(timeStr3)
    Worksheets(sheetName).Range("B" & CStr(rowCnt)).Value = CStr(rowCnt)
    Worksheets(sheetName).Range("C" & CStr(rowCnt)).Value = CStr(Cnt)
    rowCnt = rowCnt + 1

    Cnt = Cnt + 1

    If Cnt < 5 Then
        ' wait until Now + 30 seconds
        Application.OnTime TimeValue(timeStr3), "testOnTime"
    End If


End Sub

Public Sub firstSection()
    ' debug msgs for first section
    Worksheets(sheetName).Range("A" & CStr(rowCnt)).Value = "In first section @ " & CStr(timeStr2)
    Worksheets(sheetName).Range("B" & CStr(rowCnt)).Value = CStr(rowCnt)
    Worksheets(sheetName).Range("C" & CStr(rowCnt)).Value = CStr(Cnt)
    rowCnt = rowCnt + 1
    firstFlag = True
End Sub

Public Sub lastSection()
    ' debug msgs for first section
    Worksheets(sheetName).Range("A" & CStr(rowCnt)).Value = "In last section @ " & CStr(timeStr1)
    Worksheets(sheetName).Range("B" & CStr(rowCnt)).Value = CStr(rowCnt)
    Worksheets(sheetName).Range("C" & CStr(rowCnt)).Value = CStr(Cnt)
    rowCnt = rowCnt + 1
    lastFlag = True
End Sub

因此,我为每个部分实例化一个标志,该标志设置为FALSE,在宏内部,该标志将设置为TRUE。在Application.OnTime之后,我检查TRUE标志,如果不是,我等待(使用DoEvents)。这确保了在执行非阻塞OnTime之后,程序等待&#34;直到该特定宏已经执行,然后继续。这应该符合我的目的。