Bagaimana cara menjeda untuk jangka waktu tertentu? (Excel / VBA)

103

Saya memiliki lembar kerja Excel yang memiliki makro berikut. Saya ingin mengulanginya setiap detik tetapi gagal jika saya dapat menemukan fungsi untuk melakukan itu. Apa tidak mungkin?

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

Loop
End Sub
Keng
sumber

Jawaban:

129

Gunakan metode Tunggu :

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

atau (untuk Excel 2010 dan yang lebih baru):

Application.Wait Now + #12:00:01 AM#
Ben S
sumber
Saya tidak begitu yakin apa yang Anda maksud dengan itu, tetapi saya berspekulasi bahwa Anda ingin didemokan diDoEvents sini dailydoseofexcel.com/archives/2005/06/14/stopwatch
Ryan Shannon
3
@Benoit dan @Keng, Anda dapat menempatkan 1 detik secara langsung, menghindari untuk mengubah teks menjadi saat ini. Lebih bersih untuk saya: Application.Wait(Now + #0:00:01#)Cheers!
A. Sommerh
29
Format itu tidak berfungsi di Excel 2010. Namun, ini berfungsi:Application.Wait (Now + TimeValue("0:00:01"))
ZX9
1
DateAdd ("s", 1, Now) melakukan hal yang benar. Dan dapat digeneralisasikan untuk beberapa detik lama: DateAdd ("s", nSec, Now) tanpa menggunakan literal waktu. Untuk tidur kurang dari 1 detik gunakan Sleep API di kernel32
Andrew Dennison
1
@ ZX9 nilai waktu ("00:00:01") = 0,0000115740 ... Jadi Application.wait (sekarang + 0,00001) adalah sekitar satu detik. Saya suka menggunakan Application.wait(now + 1e-5)untuk satu detik, Application.wait(now + 0.5e-5)selama setengah detik, dll.
Some_Guy
61

Tambahkan ini ke modul Anda

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

Atau, untuk penggunaan sistem 64-bit:

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

Sebut saja di makro Anda seperti ini:

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

Loop
End Sub
Buggabill
sumber
1
Mengapa tidak menggunakan metode VBA untuk melakukan ini daripada menggunakan kernel32.dll?
Ben S
10
Saya telah menggunakan metode ini karena metode ini portabel di antara berbagai produk kantor seperti Access dan bukan khusus Excel.
Buggabill
Ada juga aplikasi VBA (ERS) lain yang saya gunakan yang memiliki subset bahasa yang sangat terbatas.
Buggabill
18
+1, karena Sleep()memungkinkan Anda menentukan waktu tunggu kurang dari 1 detik. Application.Waitterkadang terlalu terperinci.
BradC
2
@JulianKnight:Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
Vegard
42

daripada menggunakan:

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

saya lebih memilih:

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

karena jauh lebih mudah dibaca setelahnya.

Achaibou Karim
sumber
7
Dan berfungsi sedangkan, di Office 2013, format # 0: 0: 1 # diubah menjadi 1 detik setelah tengah malam.
Julian Knight
1
PERINGATAN: Semua solusi yang menggunakan 'Application.Wait' memiliki ketidaktepatan 1 detik. Metode ini tidak memperhitungkan milidetik yang telah berlalu sejak detik saat ini dimulai ... Misalnya, jika hanya tersisa 1 milidetik hingga detik waktu berubah, Anda hanya akan tidur selama 1 milidetik. Anda hanya membandingkan 2 angka yang dibulatkan alih-alih menunggu 1 detik!
cyberponk
18

ini bekerja dengan sempurna untuk saya. masukkan kode apa pun sebelum atau setelah loop "lakukan hingga". Dalam kasus Anda, letakkan 5 baris (time1 = & time2 = & loop "lakukan sampai") di akhir di dalam loop do Anda

sub whatever()
Dim time1, time2

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

End sub
clemo
sumber
2
Saya paling menyukai solusi ini karena saya tidak ingin menghentikan antrian pesan.
Daniel Fuchs
Solusi ini tepat dan tidak memerlukan deklarasi Fungsi-API tidur. Saya biasa menyimpan waktu dalam nilai ganda dan menggunakan mikrodetik sebagai gantinya dengan hasil yang sama.
DrMarbuse
Solusi ini bekerja lebih baik daripada solusi serupa di bawah ini yang digunakan Timerkarena Timerpendekatan gagal sebelum tengah malam.
vknowles
1
Solusi ini tidak tepat, tidak memperhitungkan milidetik yang telah berlalu dari waktu saat ini ... Misalnya, jika hanya tersisa 1 milidetik hingga detik Sekarang berubah, Anda hanya akan tidur selama 1 milidetik.
cyberponk
ketika solusi lain membutuhkan waktu lama untuk makro VBA berbasis non-MS Office, yang satu ini bekerja dengan sempurna - terima kasih!
penasaran
12

Deklarasi untuk Tidur di kernel32.dll tidak akan berfungsi di Excel 64-bit. Ini akan menjadi sedikit lebih umum:

#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
sumber
2
Gagal mengkompilasi di Office 2013. Pemeriksa kesalahan di VBA untuk Office 2013 tampaknya mengabaikan pernyataan kompiler.
Julian Knight
2
Menyusun denda untuk saya di Office 2013.
Jon Peltier
Kebanyakan orang setuju bahwa Win64 / VBA7 dwMilliseconds adalah Long, bukan LongPtr. Excel VBA menyembunyikan kesalahan seperti ini dengan melakukan koreksi tumpukan setelah panggilan eksternal, tetapi kesalahan seperti ini akan merusak sebagian besar versi Open Office
david
6

Hanya versi kode clemo yang dibersihkan - berfungsi di Access, yang tidak memiliki fungsi 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
Brian Burns
sumber
2
Jika Timermemberikan jumlah detik sejak tengah malam, maka pendekatan ini gagal jika dijalankan tepat sebelum tengah malam (misalnya sngEnd> = 86.400). Pada tengah malam, Timerreset ke 0 dan dengan demikian tetap kurang dari sngEndselamanya.
vknowles
PS Kode dari @clemo di atas berfungsi kapan saja sepanjang hari.
vknowles
@pengetahuan, apa yang Anda katakan benar-benar benar. Dan juga dapat dikompensasikan dengan metode di bawah ini. Karena metode ini menangani milidetik, saya pikir ini adalah taruhan yang aman. `` Public Sub Sleep (sngSecs As Single) Dim sngEnd As Single sngEnd = Timer + (sngSecs / 1000) While Timer <sngEnd DoEvents If (sngEnd - Timer)> 50000 Then sngEnd = sngEnd - 86400 End If Wend End Sub '' `
PravyNandas
5

Sebagian besar solusi yang disajikan menggunakan Application.Wait, yang tidak memperhitungkan waktu (milidetik) yang telah berlalu sejak penghitungan detik saat ini dimulai, sehingga solusi tersebut memiliki ketidaktepatan intrinsik hingga 1 detik .

Pendekatan Timer adalah solusi terbaik , tetapi Anda harus memperhitungkan reset pada tengah malam, jadi berikut adalah metode Tidur yang sangat tepat menggunakan 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

GUNAKAN INI UNTUK MENGUJI FUNGSI TIDUR: (buka jendela debug Segera: 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
cyberponk
sumber
3

Application.Wait Second(Now) + 1

gt
sumber
PERINGATAN: Semua solusi yang menggunakan 'Application.Wait' memiliki ketidaktepatan 1 detik. Metode ini tidak memperhitungkan milidetik yang telah berlalu sejak detik saat ini dimulai ... Misalnya, jika hanya tersisa 1 milidetik hingga detik waktu berubah, Anda hanya akan tidur selama 1 milidetik. Anda hanya membandingkan 2 angka yang dibulatkan alih-alih menunggu 1 detik!
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
ITI
sumber
1
PERINGATAN: Semua solusi yang menggunakan 'Application.Wait' memiliki ketidaktepatan 1 detik. Metode ini tidak memperhitungkan milidetik yang telah berlalu sejak detik saat ini dimulai ... Misalnya, jika hanya tersisa 1 milidetik hingga detik waktu berubah, Anda hanya akan tidur selama 1 milidetik. Anda hanya membandingkan 2 angka yang dibulatkan alih-alih menunggu 1 detik!
cyberponk
2

Berikut ini alternatif untuk tidur:

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

Dalam kode berikut saya membuat efek "cahaya" berkedip pada tombol putar untuk mengarahkan pengguna ke sana jika mereka "mengalami masalah", menggunakan "tidur 1000" di loop mengakibatkan tidak ada kedipan yang terlihat, tetapi loop berfungsi dengan baik.

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
sumber
1

Saya membuat ini untuk menjawab masalah:

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
sumber
PERINGATAN: Semua solusi yang menggunakan 'Application.Wait' memiliki ketidaktepatan 1 detik. Metode ini tidak memperhitungkan milidetik yang telah berlalu sejak detik saat ini dimulai ... Misalnya, jika hanya tersisa 1 milidetik hingga detik waktu berubah, Anda hanya akan tidur selama 1 milidetik. Anda hanya membandingkan 2 angka yang dibulatkan alih-alih menunggu 1 detik!
cyberponk
1

Saya biasanya menggunakan fungsi Timer untuk menghentikan aplikasi. Masukkan kode ini ke milik Anda

T0 = Timer
Do
    Delay = Timer - T0
Loop Until Delay >= 1 'Change this value to pause time for a certain amount of seconds
Anastasiya-Romanova 秀
sumber
3
Jika Timermemberikan jumlah detik sejak tengah malam, maka pendekatan ini gagal jika dijalankan tepat sebelum tengah malam (misalnya, T0kurang dari jumlah detik penundaan dari tengah malam). Pada tengah malam, Timersetel ulang ke 0 sebelum batas penundaan tercapai. Delaytidak pernah mencapai batas penundaan, sehingga loop berjalan selamanya.
vknowles
Karena Timer menghasilkan nilai non-integer, Anda harus menggunakan Loop Until Delay >= 1, atau Anda berisiko melewati 1 dan tidak pernah keluar dari loop.
Jon Peltier
1

Fungsi Tunggu dan Tidur mengunci Excel dan Anda tidak dapat melakukan apa pun hingga penundaan selesai. Di sisi lain, penundaan loop tidak memberi Anda waktu yang tepat untuk menunggu.

Jadi, saya telah membuat solusi ini dengan menggabungkan sedikit dari kedua konsep tersebut. Ini berulang sampai waktu yang Anda inginkan.

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

Anda hanya perlu menelepon Waste10Sec jika Anda membutuhkan penundaan

Maycow Moura
sumber
0

Coba ini :

Threading.thread.sleep(1000)
DEV
sumber
0

Anda dapat menggunakan Application.wait now + timevalue ("00:00:01") atau Application.wait now + timeserial (0,0,1)

Tuan Nguyen
sumber