Belirli bir süre nasıl duraklatılır? (Excel / VBA)


103

Aşağıdaki makroyu içeren bir Excel çalışma sayfam var. Saniyede bir döngü yapmak isterdim ama bunu yapacak işlevi bulabilirsem sersemlemiştim. Mümkün değil mi?

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

Loop
End Sub

Yanıtlar:


129

Bekle yöntemini kullanın :

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

veya (Excel 2010 ve sonrası için):

Application.Wait Now + #12:00:01 AM#

Bununla ne demek istediğinizden tam olarak emin değilim, ama DoEventsburada demo olarak istediğinizi tahmin ediyorum dailydoseofexcel.com/archives/2005/06/14/stopwatch
Ryan Shannon

3
@Benoit ve @Keng, metni bugüne dönüştürmekten kaçınarak doğrudan 1 saniye koyabilirsiniz. Benim için daha temiz: Application.Wait(Now + #0:00:01#)Şerefe!
A.Sommerh

29
Bu biçim Excel 2010'da çalışmıyordu. Yine de işe yarıyor:Application.Wait (Now + TimeValue("0:00:01"))
ZX9

1
DateAdd ("s", 1, Şimdi) doğru olanı yapar. Ve herhangi bir uzun saniye sayısı için genelleştirilebilir: Saat hazır bilgisini kullanmadan DateAdd ("s", nSec, Now). 1 saniyeden az uyumak için kernel32'de Uyku API'sini kullanın
Andrew Dennison

1
@ ZX9 zaman değeri ("00:00:01") = 0.0000115740 ... Yani Application.wait (şimdi + 0.00001) yaklaşık bir saniye. Ben kullanmak ister Application.wait(now + 1e-5), bir saniye Application.wait(now + 0.5e-5)yarım saniye vs
Some_Guy

61

Bunu modülünüze ekleyin

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

Veya 64 bit sistemler için şunları kullanın:

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

Makronuzda şöyle arayın:

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

Loop
End Sub

1
Bunu yapmak için neden kernel32.dll kullanmak yerine VBA yöntemini kullanmıyorsunuz?
Ben S

10
Bu yöntemi, Access gibi çeşitli ofis ürünleri arasında taşınabilir olduğu ve Excel'e özel olmadığı için kullandım.
Buggabill

Ayrıca çok sınırlı bir dil alt kümesine sahip kullandığım başka bir VBA uygulaması (ERS) var .
Buggabill

18
+1, çünkü Sleep()1 saniyeden daha kısa bekleme süreleri belirlemenize izin verir. Application.Waitbazen çok ayrıntılı.
BradC

2
@JulianKnight:Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
Vegard

42

kullanmak yerine:

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

tercih ederim:

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

çünkü sonradan okumak çok daha kolay.


7
Ve işe yarıyor, oysa Office 2013'te # 0: 0: 1 # biçimi gece yarısından sonra 1 saniyeye dönüşüyor.
Julian Knight

1
UYARI: 'Application.Wait' kullanan tüm çözümlerde 1 saniye belirsizlik vardır. Bu yöntem, geçerli saniyenin başlamasından bu yana geçen milisaniyeleri dikkate almaz ... Örneğin, zaman saniyeleri değişene kadar yalnızca 1 milisaniye kaldığında, yalnızca 1 milisaniye uyuyacaksınız. 1 saniye beklemek yerine sadece 2 yuvarlanmış sayıyı karşılaştırıyorsunuz!
cyberponk

18

bu benim için kusursuz çalışıyor. "yapana kadar" döngüsünden önce veya sonra herhangi bir kod ekleyin. Sizin durumunuzda, 5 satırı (time1 = & time2 = & "do to" döngüsü) do döngünüzün sonuna koyun

sub whatever()
Dim time1, time2

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

End sub

2
Bu çözümü en çok seviyorum çünkü mesaj kuyruğunu durdurmak istemedim.
Daniel Fuchs

Bu çözüm kesindir ve sleep-API-Function bildirimini gerektirmez. Zamanı çift değerlerle saklardım ve bunun yerine aynı sonuçla mikrosaniyeler kullanırdım.
DrMarbuse

Bu çözüm, aşağıdaki benzer çözümlerden daha iyi çalışıyor Timerçünkü Timeryaklaşım gece yarısından hemen önce başarısız oluyor.
vknowles

1
Bu çözüm kesin değildir, şimdiki zamandan halihazırda geçen milisaniyeleri hesaba katmaz ... Örneğin, Şimdi saniyeler değişene kadar yalnızca 1 milisaniye kalmışsa, yalnızca 1 milisaniye uyuyacaksınız.
cyberponk

MS Office tabanlı olmayan bir VBA makrosu için diğer çözümler uzun zaman aldığında, bu mükemmel çalıştı - teşekkürler!
meraklı

12

Kernel32.dll'deki Uyku bildirimi 64 bit Excel'de çalışmaz. Bu biraz daha genel olurdu:

#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'te derleme başarısız. Office 2013 için VBA'daki hata denetleyicisi, derleyici bildirimlerini yok sayıyor gibi görünüyor.
Julian Knight

2
Office 2013'te benim için iyi derler.
Jon Peltier

Çoğu kişi Win64 / VBA7 dwMilliseconds'un LongPtr değil, Long olduğunu kabul eder. Excel VBA, harici aramalardan sonra yığın düzeltmesi yaparak bunun gibi hataları gizler, ancak bunun gibi hatalar çoğu Open Office sürümünün çökmesine neden olur
david

6

Yalnızca clemo kodunun temizlenmiş bir sürümü - Application.Wait işlevine sahip olmayan Access'te çalışır.

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
Eğer Timergece yarısından itibaren saniye sayısını verir sadece gece yarısından önce yürütülür, sonra bu yaklaşım başarısız (yani öyle ki sngEnd> = 86.400) olduğunu. Gece yarısı Timer0'a sıfırlanır ve bu nedenle sngEndsonsuza kadar kalmaz .
vknowles

Not: Yukarıdaki @clemo kodu günün her saatinde çalışır.
vknowles

@vknowles, söyledikleriniz kesinlikle doğru. Ve ayrıca aşağıdaki yöntemle telafi edilebilir. Bu yöntem milisaniyeleri işlediğinden, bunun güvenli bir bahis olduğunu düşünüyorum. `` `` Public Sub Sleep (sngSecs As Single) Dim sngEnd As Single sngEnd = Timer + (sngSecs / 1000) When Timer <sngEnd DoEvents If (sngEnd - Timer)> 50000 Then sngEnd = sngEnd - 86400 End If Wend End Sub '' `
PravyNandas

5

Sunulan çözümlerin çoğu, akımın saniye sayımının başlamasından bu yana geçen süreyi (milisaniye) hesaba katmayan Application.Wait'i kullanır, bu nedenle 1 saniyeye kadar içsel bir belirsizliğe sahiptirler .

Zamanlayıcı yaklaşımı en iyi çözümdür , ancak gece yarısı sıfırlamayı hesaba katmanız gerekir, bu yüzden işte Zamanlayıcı kullanan çok hassas bir Uyku yöntemi:

'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

HERHANGİ BİR UYKU FONKSİYONUNU TEST ETMEK İÇİN BUNU KULLANIN: (hata ayıklama Anında penceresini aç: 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

3

Application.Wait Second(Now) + 1


UYARI: 'Application.Wait' kullanan tüm çözümlerde 1 saniye belirsizlik vardır. Bu yöntem, geçerli saniyenin başlamasından bu yana geçen milisaniyeleri dikkate almaz ... Örneğin, zaman saniyeleri değişene kadar yalnızca 1 milisaniye kaldığında, yalnızca 1 milisaniye uyuyacaksınız. 1 saniye beklemek yerine sadece 2 yuvarlanmış sayıyı karşılaştırıyorsunuz!
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

1
UYARI: 'Application.Wait' kullanan tüm çözümlerde 1 saniye belirsizlik vardır. Bu yöntem, geçerli saniyenin başlamasından bu yana geçen milisaniyeleri dikkate almaz ... Örneğin, zaman saniyeleri değişene kadar yalnızca 1 milisaniye kaldığında, yalnızca 1 milisaniye uyuyacaksınız. 1 saniye beklemek yerine sadece 2 yuvarlanmış sayıyı karşılaştırıyorsunuz!
cyberponk

2

İşte uyumaya bir alternatif:

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

Aşağıdaki kodda, kullanıcıları "sorun yaşıyorlarsa" yönlendirmek için bir döndürme düğmesinde "parlama" efekti yanıp sönerim, döngüde "uyku 1000" kullanmak görünür bir yanıp sönmeye neden olmaz, ancak döngü harika çalışıyor.

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

1

soruna cevap vermek için bunu yaptırdım:

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

UYARI: 'Application.Wait' kullanan tüm çözümlerde 1 saniye belirsizlik vardır. Bu yöntem, geçerli saniyenin başlamasından bu yana geçen milisaniyeleri dikkate almaz ... Örneğin, zaman saniyeleri değişene kadar yalnızca 1 milisaniye kaldığında, yalnızca 1 milisaniye uyuyacaksınız. 1 saniye beklemek yerine sadece 2 yuvarlanmış sayıyı karşılaştırıyorsunuz!
cyberponk

1

Uygulamayı duraklatmak için genellikle Zamanlayıcı işlevini kullanıyorum . Bu kodu kendinize ekleyin

T0 = Timer
Do
    Delay = Timer - T0
Loop Until Delay >= 1 'Change this value to pause time for a certain amount of seconds

3
Eğer Timergece yarısından itibaren saniye sayısını verir sadece gece yarısından önce yürütülür, sonra bu yaklaşım başarısız (yani öyle ki T0daha az yarısından gecikme saniye sayısı daha). Gece yarısı, Timergecikme sınırına ulaşılmadan önce 0'a sıfırlanır. Delayasla gecikme sınırına ulaşmaz, bu nedenle döngü sonsuza kadar çalışır.
vknowles

Timer tamsayı olmayan değerler ürettiğinden, kullanmalısınız Loop Until Delay >= 1, yoksa 1'in üzerine çıkıp döngüden asla çıkmama riskini alırsınız.
Jon Peltier

1

Bekleme ve Uyku işlevleri Excel'i kilitler ve gecikme bitene kadar başka bir şey yapamazsınız. Öte yandan, Döngü gecikmeleri size beklemek için kesin bir zaman vermez.

Bu yüzden, her iki kavramı da biraz birleştirerek bu geçici çözümü yaptım. Saat, istediğiniz zaman olana kadar döngüye girer.

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

Gecikmeye ihtiyaç duyduğunuz yerde Waste10Sec'i aramanız yeterlidir


0

Bunu dene :

Threading.thread.sleep(1000)

0

Application.wait now + timevalue ("00:00:01") veya Application.wait now + timeserial (0,0,1) kullanabilirsiniz

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.