How to implement sleep/wait with VBA

Excel-Sleep

Ok, everybody need this. Every single programmer that I’ve known once in his miserable life needed to do this in your programs. Alright, this is too dramatic, but it’s true. The problem is, in VBA, there is no easy going way to find a “how to do this”, like it is in other languages. But don’t worry. I’m here to save your lives, or something like that. Ok, too dramatic again.

With VBA, there are a couple of ways to do this.

First Method: Use an empty loop For… Next

The problem here is that you don’t have any control on how long it will take/sleep/wait/whatever. It’s just a way to make your program do nothing for a while. The code below runs for a while, given to the user the impression of be waiting.

1
2
3
4
Sub MyDelayMacro
 For iCount = 1 to 1000
 Next iCount
End Sub

Second Method: Use an API to call the Sleep method

Yes, there a Sleep method which can be called from VBA! This causes the same effect as the other programs, holding the process of the program for a defined amount of time, in milliseconds.

The kernel32 lib contains this method, so, you need to declare it in the top module to call it.

1
2
   Declare Sub Sleep Lib "kernel32" Alias "Sleep" _
 (ByVal dwMilliseconds As Long)

To call the Sleep method::

1
2
3
Sub Sleep()
 Sleep 1000   'Faz o código esperar por 1 segundo
 End Sub

Third Method: Use the OnTime Method

Actually, it’s my favourite. The OnTime method is embedded in VBA and the programmers are often used to it. The syntax is a bit weird, but it works!

expression .OnTime (when, name, fail tolerance)

It requires the name of the macro/method which will be called after some time, which is the first argument of the method. So, as it seems to be, you will need two macros. The first one will activate the OnTime, while the second will be called by the OnTime.

In the code below, the “MyMainMacro” activate the OnTime to call “MyDelayMacro” after 15 seconds.

1
2
3
4
5
6
7
8
Sub MyMainMacro()
 ' Pausa por 15 segundos.
 Application.OnTime Now + TimeValue("00:00:15"), "MyDelayMacro"
 End Sub
Public Sub MyDelayMacro()
 ' Macro executada sob o agendamento.
 MsgBox "Esta macro foi executada após 15 segundos."
 End Sub

Fourth Method: Call the Application.Wait method

It’s similar to Sleep, but instead of send the amount of seconds as an argument, you need to build a TimeValue variable to send as a parameter. You need to think a bit different to use, because the program will wait to the time you have defined. Let’s see take a look at the code:

1
2
3
4
5
6
7
Sub MyWaitMacro()
newHour = Hour(Now())
newMinute = Minute(Now())
newSecond = Second(Now()) + 3
waitTime = TimeSerial(newHour, newMinute, newSecond)
Application.Wait waitTime
End Sub

To read more about the OnTime method, check this post: https://www.tomasvasquez.com.br/blog/microsoft-office/vba-agendando-a-execucao-de-macros-com-a-funcao-ontime

Enjoy!

Comentários

comentários

11 thoughts on “How to implement sleep/wait with VBA”

  1. Me ajuda, não consigo utilizar o Application.ontime dentro do userform. O problema é que ele funciona, mas não chama a sub que eu peço.
    Eu preciso é que a rotina espere um tempo e execute uma sub.
    Pode me ajudar ?

  2. Oi Tomás,

    Estou desenvolvendo uma macro que navega entre páginas de um website. Será que vc saberia como faço para que um determinado trecho de código seja executado apenas depois que uma determinada página for carregada? Não posso usar nenhuma das opções acima por serem muito estáticas, e o carregamento de uma página no browser varia de acordo com diversos parâmetros (velocidade conexão, processador, e outros).

    Agradeço se puder ajudar.

  3. Oi,

    Desculpe, pois eu realmente não conheco muita coisa de vba e preciso disso para finalizar um projeto.
    Dei uma olhada no post que você sugeriu, mas não entendi o que seria o READYSTATE_COMPLETE, pois ao depurar, percebi que não possuia valor, travando a minha aplicação, e pesquisando na internet algumas pessoas atribuem o valor 4, e dessa maneira a aplicação não aguarda o carregamento completo da página.

    Você pode me esclarecer esta dúvida?

    Agradeço.

  4. Estou tentando utilizar o Application.ontime porem indica que eu não possuo ele,

    Public Sub IniciarTeste()
    Alarme = Now TimeSerial(0, 0, IntervaloSegundos)
    Application.OnTime EarliestTime:=Alarme, procedure:=”Macro1″, schedule:=True

    Application

    End Sub

    Public Sub Macro1()
    ‘As suas rotinas
    MsgBox “Olá!!! voltarei pelas ” & Format(Alarme, “hh:mm:ss”), _
    vbInformation, “Timer em Vba”
    Call IniciarTeste
    End Sub

    Public Sub PararTeste()
    On Error Resume Next
    Application.OnTime EarliestTime:=Alarme, _
    procedure:=”Macro1″, _
    schedule:=False
    End Sub

    Esta tudo declarado dentro de um formulário, isto esta correto?
    Tenho que declarar em outro lugar ou algo assim?
    Por que ele indica pra mim que não tenho o OnTime no meu projeto?

    Att

    Thomas

  5. Thomas,

    É preciso entender o que quer realmente fazer. No seu código, aparentemente há uma referência circular e isso deve ser tratado.

    Respondendo a algumas perguntas:
    Esta tudo declarado dentro de um formulário, isto esta correto?
    O OnTime funcionará da mesma forma. Porém, é uma “boa prática” deixar funções em Módulos separados
    Tenho que declarar em outro lugar ou algo assim?
    Respondido acima
    Por que ele indica pra mim que não tenho o OnTime no meu projeto?
    Provável que haja algum erro no código. A função OnTime é nativa do VBA quando acesso pela maioria das aplicações do Office.

    Abraços
    Tomás

  6. Bom dia Tomas,
    Estou fazendo um cronometro , e preciso que ele seja regressivo e que tbm receba os valores em minutos que eu determinar, mais não consegui fazer pois entendo pouco de VBA, porém tenho esse código que montei:

    Private Sub Resetar_Click()
    dteStopped = 0
    dteStart = 0
    dteElapsed = 0
    Label1 = “00:00:00”
    boolResetPressed = True
    End Sub

    Private Sub iniciar_Click()
    Start_timer:
    dteStart = Time
    boolStopPressed = False
    boolResetPressed = False
    Timer_Loop:
    DoEvents
    dteFinish = Time
    dteElapsed = dteFinish – dteStart + dteStopped
    If Not boolStopPressed = True Then
    Label1 = dteElapsed
    If boolResetPressed = True Then GoTo Start_timer
    GoTo Timer_Loop
    Else
    Exit Sub
    End If
    End Sub

    Private Sub parar_Click()
    boolStopPressed = True
    dteStopped = dteElapsed
    End Sub

    Private Sub btnReset_Click()
    dteStopped = 0
    dteStart = 0
    dteElapsed = 0
    Label1 = “00:00:00”
    boolResetPressed = True
    End Sub

    Private Sub btnStart_Click()
    Start_timer:
    dteStart = Time
    boolStopPressed = False
    boolResetPressed = False
    Timer_Loop:
    DoEvents
    dteFinish = Time
    dteElapsed = dteFinish – dteStart + dteStopped
    If Not boolStopPressed = True Then
    Label1 = dteElapsed
    If boolResetPressed = True Then GoTo Start_timer
    GoTo Timer_Loop
    Else
    Exit Sub
    End If
    End Sub

    Private Sub btnStop_Click()
    boolStopPressed = True
    dteStopped = dteElapsed
    End Sub

    gostaria de sua ajuda para deixa-lo da forma que preciso. recebendo valores em minutos e regredindo até zerar, e se possível qnd chegar a 00:00 ele alarme e apareça uma msg na tela.

    DESDE JÁ, OBRIGADO, abraços

  7. Tomás, gostaria de implementar atraso em meu código que é direcionado a preencher dados em um WEBSite, atualmente uso a função Sleep o que faz ele dormir por alguns segundos até a pagina ser totalmente carregada. Tentei utilizar as 3 rotinas abaixo sem exito pois a pagina carrega alguns “TextBox” depois de carregada e a função Sleep não esta ajudando na produtividade de meu trabalho, Consegue me conceder esta ajuda? pensei em fazer um loop no textBox se ele estiver visível mas sem exito tbm. Grato pela atenção!

    Do While ie.Busy
    Loop
    ””””””””””””’
    Do Until ie.Document.ReadyState = “complete”
    Loop
    ””””””””””””’
    Do Until ie.ReadyState = READYSTATE_COMPLETE
    Loop

Comments are closed.