Wie kann ich für eine bestimmte Zeitspanne pausieren? (Excel / VBA)

103

Ich habe ein Excel-Arbeitsblatt mit dem folgenden Makro. Ich würde es gerne jede Sekunde wiederholen, aber es ist schwierig, wenn ich die Funktion dafür finde. Ist das nicht möglich

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

Loop
End Sub
Keng
quelle

Antworten:

128

Verwenden Sie die Wait-Methode :

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

oder (für Excel 2010 und höher):

Application.Wait Now + #12:00:01 AM#
Ben S.
quelle
Ich bin mir nicht ganz sicher, was Sie damit meinen, aber ich spekuliere, dass Sie möchten, DoEventswie hier gezeigt. Dailydoseofexcel.com/archives/2005/06/14/stopwatch
Ryan Shannon
3
@Benoit und @Keng können Sie 1 Sekunde direkt eingeben, ohne Text auf den neuesten Stand zu bringen. Ist sauberer für mich: Application.Wait(Now + #0:00:01#)Prost!
A. Sommerh
29
Dieses Format funktionierte in Excel 2010 nicht. Dies funktioniert jedoch:Application.Wait (Now + TimeValue("0:00:01"))
ZX9
1
DateAdd ("s", 1, Now) macht das Richtige. Und kann für eine beliebige Anzahl von Sekunden verallgemeinert werden: DateAdd ("s", nSec, Now) ohne Verwendung des Zeitliteral. Um weniger als 1 Sekunde zu schlafen, verwenden Sie die Schlaf-API in Kernel32
Andrew Dennison
1
@ ZX9-Zeitwert ("00:00:01") = 0,0000115740 ... Application.wait (jetzt + 0,00001) dauert also ungefähr eine Sekunde. Ich benutze es gerne Application.wait(now + 1e-5)für eine Sekunde, Application.wait(now + 0.5e-5)für eine halbe Sekunde usw.
Some_Guy
61

Fügen Sie dies Ihrem Modul hinzu

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

Oder verwenden Sie für 64-Bit-Systeme:

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

Nennen Sie es in Ihrem Makro wie folgt:

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

Loop
End Sub
Buggabill
quelle
1
Warum nicht die VBA-Methode verwenden, anstatt kernel32.dll zu verwenden?
Ben S
10
Ich habe diese Methode verwendet, da sie zwischen den verschiedenen Office-Produkten wie Access portierbar ist und nicht Excel-spezifisch ist.
Buggabill
Es gibt auch eine andere VBA-Anwendung (ERS), die ich verwende und die nur eine sehr begrenzte Teilmenge der Sprache enthält.
Buggabill
18
+1, da Sleep()Sie Wartezeiten von weniger als 1 Sekunde angeben können. Application.Waitist manchmal zu körnig.
BradC
2
@ JulianKnight:Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
Vegard
42

anstatt zu verwenden:

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

ich bevorzuge:

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

weil es danach viel einfacher zu lesen ist.

Achaibou Karim
quelle
7
Und es funktioniert, während in Office 2013 das Format # 0: 0: 1 # nach Mitternacht in 1 Sekunde konvertiert wird.
Julian Knight
1
WARNUNG: Alle Lösungen, die 'Application.Wait' verwenden, weisen eine Ungenauigkeit von 1 Sekunde auf. Bei dieser Methode werden die Millisekunden nicht berücksichtigt, die bereits seit dem Start der aktuellen Sekunde verstrichen sind. Wenn beispielsweise nur noch 1 Millisekunde übrig ist, bis sich die Sekunden ändern, werden Sie nur 1 Millisekunde lang schlafen. Sie vergleichen nur 2 gerundete Zahlen, anstatt 1 Sekunde zu warten!
Cyberponk
18

Das funktioniert einwandfrei für mich. Fügen Sie einen beliebigen Code vor oder nach der "do till" -Schleife ein. Fügen Sie in Ihrem Fall die 5 Zeilen (time1 = & time2 = & "do till" -Schleife) am Ende Ihrer do-Schleife ein

sub whatever()
Dim time1, time2

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

End sub
Clemo
quelle
2
Diese Lösung gefällt mir am besten, weil ich die Nachrichtenwarteschlange nicht anhalten wollte.
Daniel Fuchs
Diese Lösung ist präzise und erfordert keine Deklaration der Sleep-API-Funktion. Ich habe die Zeit in doppelten Werten gespeichert und stattdessen Mikrosekunden mit dem gleichen Ergebnis verwendet.
DrMarbuse
Diese Lösung funktioniert besser als die ähnlichen Lösungen, Timerda der TimerAnsatz kurz vor Mitternacht fehlschlägt.
vknowles
1
Diese Lösung ist nicht präzise und berücksichtigt nicht die Millisekunden, die bereits seit der aktuellen Zeit verstrichen sind. Wenn beispielsweise nur noch 1 Millisekunde übrig ist, bis sich die Jetzt-Sekunden ändern, werden Sie nur 1 Millisekunde lang schlafen.
Cyberponk
Als andere Lösungen für ein nicht auf MS Office basierendes VBA-Makro lange brauchten, funktionierte dieses perfekt - danke!
neugierig
12

Die Deklaration für Sleep in kernel32.dll funktioniert in 64-Bit-Excel nicht. Dies wäre etwas allgemeiner:

#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
dbuskirk
quelle
2
Kompiliert in Office 2013 nicht. Die Fehlerprüfung in VBA für Office 2013 scheint die Compiler-Anweisungen zu ignorieren.
Julian Knight
2
Kompiliert gut für mich in Office 2013.
Jon Peltier
Die meisten Leute sind sich einig, dass Win64 / VBA7 dwMilliseconds Long ist, nicht LongPtr. Excel VBA verbirgt solche Fehler, indem es nach externen Aufrufen eine Stapelkorrektur durchführt. Fehler wie diese führen jedoch zum Absturz der meisten Versionen von Open Office
David
6

Nur eine bereinigte Version von Clemos Code - funktioniert in Access, das nicht über die Application.Wait-Funktion verfügt.

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
Brian Burns
quelle
2
Wenn Timerdie Anzahl der Sekunden seit Mitternacht angegeben wird, schlägt dieser Ansatz fehl, wenn er kurz vor Mitternacht ausgeführt wird (dh sngEnd> = 86.400). TimerWird um Mitternacht auf 0 zurückgesetzt und bleibt somit weniger als sngEndfür immer.
vknowles
PS Der Code von @clemo oben funktioniert zu jeder Tageszeit.
vknowles
@vknowles, was du gesagt hast ist absolut wahr. Und kann auch in der folgenden Methode kompensiert werden. Da diese Methode Millisekunden verarbeitet, halte ich es für eine sichere Sache. `` `Public Sub Sleep (sngSecs als Single) Dim sngEnd als Single sngEnd = Timer + (sngSecs / 1000) Während Timer <sngEnd DoEvents If (sngEnd - Timer)> 50000 Dann sngEnd = sngEnd - 86400 End If Wend End Sub` ` `
PravyNandas
5

Die meisten der vorgestellten Lösungen verwenden Application.Wait, das die Zeit (Millisekunden) nicht berücksichtigt, die bereits seit Beginn der aktuellen Sekundenzählung verstrichen ist, sodass sie eine intrinsische Ungenauigkeit von bis zu 1 Sekunde aufweisen .

Der Timer-Ansatz ist die beste Lösung , aber Sie müssen das Zurücksetzen um Mitternacht berücksichtigen. Hier ist eine sehr genaue Schlafmethode mit 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

VERWENDEN SIE DIESES, UM JEDE SCHLAFFUNKTION ZU TESTEN: (Debug öffnen Sofortiges Fenster: STRG + 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
Cyberponk
quelle
3

Application.Wait Second(Now) + 1

gt
quelle
WARNUNG: Alle Lösungen, die 'Application.Wait' verwenden, weisen eine Ungenauigkeit von 1 Sekunde auf. Bei dieser Methode werden die Millisekunden nicht berücksichtigt, die bereits seit dem Start der aktuellen Sekunde verstrichen sind. Wenn beispielsweise nur noch 1 Millisekunde übrig ist, bis sich die Sekunden ändern, werden Sie nur 1 Millisekunde lang schlafen. Sie vergleichen nur 2 gerundete Zahlen, anstatt 1 Sekunde zu warten!
Cyberponk
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
ES I
quelle
1
WARNUNG: Alle Lösungen, die 'Application.Wait' verwenden, weisen eine Ungenauigkeit von 1 Sekunde auf. Bei dieser Methode werden die Millisekunden nicht berücksichtigt, die bereits seit dem Start der aktuellen Sekunde verstrichen sind. Wenn beispielsweise nur noch 1 Millisekunde übrig ist, bis sich die Sekunden ändern, werden Sie nur 1 Millisekunde lang schlafen. Sie vergleichen nur 2 gerundete Zahlen, anstatt 1 Sekunde zu warten!
Cyberponk
2

Hier ist eine Alternative zum Schlafen:

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

Im folgenden Code lasse ich einen "Glow" -Effekt auf einer Drehschaltfläche blinken, um Benutzer darauf hinzuweisen, wenn sie "Probleme" haben. Die Verwendung von "sleep 1000" in der Schleife führte zu keinem sichtbaren Blinken, aber die Schleife funktioniert hervorragend.

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
Reverus
quelle
1

Ich ließ dies machen, um das Problem zu beantworten:

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
Dave
quelle
WARNUNG: Alle Lösungen, die 'Application.Wait' verwenden, weisen eine Ungenauigkeit von 1 Sekunde auf. Bei dieser Methode werden die Millisekunden nicht berücksichtigt, die bereits seit dem Start der aktuellen Sekunde verstrichen sind. Wenn beispielsweise nur noch 1 Millisekunde übrig ist, bis sich die Sekunden ändern, werden Sie nur 1 Millisekunde lang schlafen. Sie vergleichen nur 2 gerundete Zahlen, anstatt 1 Sekunde zu warten!
Cyberponk
1

Normalerweise verwende ich die Timer- Funktion, um die Anwendung anzuhalten . Fügen Sie diesen Code in Ihren ein

T0 = Timer
Do
    Delay = Timer - T0
Loop Until Delay >= 1 'Change this value to pause time for a certain amount of seconds
Anastasiya-Romanova 秀
quelle
3
Wenn Timerdie Anzahl der Sekunden seit Mitternacht angegeben wird, schlägt dieser Ansatz fehl, wenn er kurz vor Mitternacht ausgeführt wird (dh T0weniger als die Anzahl der Verzögerungssekunden ab Mitternacht). TimerWird um Mitternacht auf 0 zurückgesetzt, bevor das Verzögerungslimit erreicht ist. Delayerreicht nie die Verzögerungsgrenze, daher läuft die Schleife für immer.
vknowles
Da der Timer nicht ganzzahlige Werte erzeugt, sollten Sie diese verwenden Loop Until Delay >= 1, da sonst die Gefahr besteht, dass Sie über 1 hinausgehen und die Schleife niemals verlassen.
Jon Peltier
1

Wait and Sleep-Funktionen sperren Excel und Sie können nichts anderes tun, bis die Verzögerung beendet ist. Auf der anderen Seite geben Ihnen Loop-Verzögerungen keine genaue Wartezeit.

Also habe ich diese Problemumgehung gemacht, um ein wenig von beiden Konzepten zu verbinden. Es wird so lange wiederholt, bis die gewünschte Zeit erreicht ist.

Private Sub Waste10Sec()
   target = (Now + TimeValue("0:00:10"))
   Do
       DoEvents 'keeps excel running other stuff
   Loop Until Now >= target
End Sub

Sie müssen nur Waste10Sec anrufen, wo Sie die Verzögerung benötigen

Maycow Moura
quelle
0

Versuche dies :

Threading.thread.sleep(1000)
DEV
quelle
0

Sie können Application.wait now + timevalue ("00:00:01") oder Application.wait now + timeserial (0,0,1) verwenden.

Tuan Nguyen
quelle