Как сделать паузу на определенное количество времени? (Excel / VBA)

92

У меня есть рабочий лист Excel, который имеет следующий макрос. Я хотел бы зацикливать его каждую секунду, но меня можно использовать, если я могу найти функцию для этого. Разве это невозможно?

Sub Macro1()
'
' Macro1 Macro
'
Do
    Calculate
    'Here I want to wait for one second

Loop
End Sub
Теги:
excel-vba
excel

13 ответов

116
Лучший ответ

Используйте Метод ожидания:

Application.Wait Now + #0:00:01#

или (для Excel 2010 и более поздних версий):

Application.Wait Now + #12:00:01 AM#
  • 0
    СПАСИБО!!! Есть ли более изящный способ остановить его, чем использовать «Esc»?
  • 0
    Я не совсем уверен, что вы подразумеваете под этим, но я полагаю, вы хотите, чтобы DoEvents демонстрировался здесь dailydoseofexcel.com/archives/2005/06/14/stopwatch
Показать ещё 9 комментариев
57

Добавьте это в свой модуль

Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Или, для 64-битных систем используйте:

Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)

Позвоните в свой макрос следующим образом:

Sub Macro1()
'
' Macro1 Macro
'
Do
    Calculate
    Sleep (1000) ' delay 1 second

Loop
End Sub
  • 1
    Почему бы не использовать метод VBA, чтобы сделать это, а не с помощью kernel32.dll?
  • 9
    Я использовал этот метод, поскольку он переносим между различными офисными продуктами, такими как Access, и не является специфичным для Excel.
Показать ещё 7 комментариев
37

вместо использования:

Application.Wait(Now + #0:00:01#)

Я предпочитаю:

Application.Wait(Now + TimeValue("00:00:01"))

потому что после этого читать намного легче.

  • 7
    И это работает, тогда как в Office 2013 формат # 0: 0: 1 # конвертируется в 1 секунду после полуночи.
  • 0
    ВНИМАНИЕ: Все решения, использующие «Application.Wait», имеют погрешность в 1 секунду. Этот метод не учитывает миллисекунды, которые уже прошли с начала текущей секунды ... Например, если до изменения секунд времени остается только 1 миллисекунда, вы будете спать только 1 миллисекунду. Вы просто сравниваете 2 округленных числа вместо того, чтобы ждать 1 секунду!
15

это безупречно работает для меня. вставьте любой код до или после цикла "делать до". В вашем случае поставьте 5 строк (time1 = и time2 = и "do until" ) в конце внутри цикла do

sub whatever()
Dim time1, time2

time1 = Now
time2 = Now + TimeValue("0:00:01")
    Do Until time1 >= time2
        DoEvents
        time1 = Now()
    Loop

End sub
  • 1
    Мне больше всего нравится это решение, потому что я не хотел останавливать очередь сообщений.
  • 0
    Это решение является точным и не требует объявления функции Sleep API. Я имел обыкновение хранить время в двойных значениях и использовать вместо этого микросекунды с тем же результатом.
Показать ещё 3 комментария
12

Объявление для сна в файле kernel32.dll не будет работать в 64-разрядном Excel. Это будет немного более общим:

#If VBA7 Then
    Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else
    Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If
  • 2
    Не удается скомпилировать в Office 2013. Средство проверки ошибок в VBA для Office 2013, похоже, игнорирует операторы компилятора.
  • 2
    Компилирует нормально для меня в Office 2013.
Показать ещё 1 комментарий
5

Просто очищенная версия кода clemo - работает в Access, у которой нет функции Application.Wait.

Public Sub Pause(sngSecs As Single)
    Dim sngEnd As Single
    sngEnd = Timer + sngSecs
    While Timer < sngEnd
        DoEvents
    Wend
End Sub

Public Sub TestPause()
    Pause 1
    MsgBox "done"
End Sub
  • 2
    Если Timer дает количество секунд с полуночи, то этот подход не срабатывает, если он выполняется незадолго до полуночи (т. sngEnd Такой, что sngEnd >> 86 400). В полночь Timer сбрасывается до 0 и, таким образом, остается меньше sngEnd навсегда.
  • 0
    PS Код из @clemo выше работает в любое время суток.
3

Application.Wait Second(Now) + 1

  • 0
    ВНИМАНИЕ: Все решения, использующие «Application.Wait», имеют погрешность в 1 секунду. Этот метод не учитывает миллисекунды, которые уже прошли с начала текущей секунды ... Например, если до изменения секунд времени остается только 1 миллисекунда, вы будете спать только 1 миллисекунду. Вы просто сравниваете 2 округленных числа вместо того, чтобы ждать 1 секунду!
2

Вот альтернатива для сна:

Sub TDelay(delay As Long)
Dim n As Long
For n = 1 To delay
DoEvents
Next n
End Sub

В следующем коде я заставляю мигать эффект "свечения" на кнопке прокрутки, чтобы направить пользователей к ней, если у них "возникли проблемы", использование "sleep 1000" в цикле не привело к видимому миганию, но цикл работает отлично.

Sub SpinFocus()
Dim i As Long
For i = 1 To 3   '3 blinks
Worksheets(2).Shapes("SpinGlow").ZOrder (msoBringToFront)
TDelay (10000)   'this makes the glow stay lit longer than not, looks nice.
Worksheets(2).Shapes("SpinGlow").ZOrder (msoSendBackward)
TDelay (100)
Next i
End Sub
2
Function Delay(ByVal T As Integer)
    'Function can be used to introduce a delay of up to 99 seconds
    'Call Function ex:  Delay 2 {introduces a 2 second delay before execution of code resumes}
        strT = Mid((100 + T), 2, 2)
            strSecsDelay = "00:00:" & strT
    Application.Wait (Now + TimeValue(strSecsDelay))
End Function
  • 0
    ВНИМАНИЕ: Все решения, использующие «Application.Wait», имеют погрешность в 1 секунду. Этот метод не учитывает миллисекунды, которые уже прошли с начала текущей секунды ... Например, если до изменения секунд времени остается только 1 миллисекунда, вы будете спать только 1 миллисекунду. Вы просто сравниваете 2 округленных числа вместо того, чтобы ждать 1 секунду!
1

В большинстве представленных решений используется Application.Wait, который не учитывает время (миллисекунды), уже прошедшее с момента начала подсчета секунды, поэтому им присуща неточность до 1 секунды.

Подход с таймером является наилучшим решением, но вы должны принять во внимание сброс в полночь, поэтому вот очень точный метод Sleep с использованием Timer:

'You can use integer (1 for 1 second) or single (1.5 for 1 and a half second)
Public Sub Sleep(vSeconds As Variant)
    Dim t0 As Single, t1 As Single
    t0 = Timer
    Do
        t1 = Timer
        If t1 < t0 Then t1 = t1 + 86400 'Timer overflows at midnight
        DoEvents    'optional, to avoid excel freeze while sleeping
    Loop Until t1 - t0 >= vSeconds
End Sub

ИСПОЛЬЗУЙТЕ ЭТО ДЛЯ ТЕСТИРОВАНИЯ ЛЮБОЙ ФУНКЦИИ СНА: (откройте окно отладки: CTRL + G)

Sub testSleep()
    t0 = Timer
    Debug.Print "Time before sleep:"; t0   'Timer format is in seconds since midnight

    Sleep (1.5)

    Debug.Print "Time after sleep:"; Timer
    Debug.Print "Slept for:"; Timer - t0; "seconds"

End Sub
1

Я обычно использую функцию таймера, чтобы приостановить приложение. Вставьте этот код в свой

T0 = Timer
Do
    Delay = Timer - T0
Loop Until Delay >= 1 'Change this value to pause time for a certain amount of seconds
  • 1
    Если Timer дает количество секунд с полуночи, то этот подход не срабатывает, если он выполняется незадолго до полуночи (то есть такой, что T0 меньше, чем число секунд задержки с полуночи). В полночь Timer сбрасывается на 0 до того, как будет достигнут предел задержки. Delay никогда не достигает предела задержки, поэтому цикл работает вечно.
  • 0
    Поскольку Timer выдает нецелые значения, вы должны использовать Loop Until Delay >= 1 , иначе вы рискуете перейти через 1 и никогда не выходить из цикла.
1

Я сделал это, чтобы ответить на проблему:

Sub goTIMER(NumOfSeconds As Long) 'in (seconds) as:  call gotimer (1)  'seconds
  Application.Wait now + NumOfSeconds / 86400#
  'Application.Wait (Now + TimeValue("0:00:05"))  'other
  Application.EnableEvents = True       'EVENTS
End Sub
  • 0
    ВНИМАНИЕ: Все решения, использующие «Application.Wait», имеют погрешность в 1 секунду. Этот метод не учитывает миллисекунды, которые уже прошли с начала текущей секунды ... Например, если до изменения секунд времени остается только 1 миллисекунда, вы будете спать только 1 миллисекунду. Вы просто сравниваете 2 округленных числа вместо того, чтобы ждать 1 секунду!
0

Попробуйте следующее:

Threading.thread.sleep(1000)
  • 0
    Не будет работать по умолчанию

Ещё вопросы

Сообщество Overcoder
Наверх
Меню