จะหยุดชั่วคราวตามระยะเวลาที่กำหนดได้อย่างไร? (Excel / VBA)


103

ฉันมีแผ่นงาน Excel ที่มีมาโครต่อไปนี้ ฉันอยากจะวนซ้ำทุก ๆ วินาที แต่ถ้าฉันสามารถหาฟังก์ชั่นนี้ได้ เป็นไปไม่ได้เหรอ?

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

Loop
End Sub

คำตอบ:


129

ใช้วิธีการรอ :

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

หรือ (สำหรับ Excel 2010 ขึ้นไป):

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

ฉันไม่แน่ใจว่าคุณหมายถึงอะไร แต่ฉันคาดเดาว่าคุณต้องการDoEventsตามตัวอย่างที่นี่dailydoseofexcel.com/archives/2005/06/14/stopwatch
Ryan Shannon

3
@Benoit และ @Keng คุณสามารถใส่ 1 วินาทีได้โดยตรงโดยหลีกเลี่ยงการแปลงข้อความเป็นวันที่ สะอาดมากขึ้นสำหรับฉัน: Application.Wait(Now + #0:00:01#)ไชโย!
อาทิตย์

29
รูปแบบดังกล่าวใช้ไม่ได้ใน Excel 2010 ซึ่งใช้ได้แม้ว่า:Application.Wait (Now + TimeValue("0:00:01"))
ZX9

1
DateAdd ("s", 1, Now) ทำสิ่งที่ถูกต้อง และสามารถกำหนดโดยทั่วไปสำหรับจำนวนวินาทีที่ยาว: DateAdd ("s", nSec, Now) โดยไม่ต้องใช้ตัวอักษรเวลา หากต้องการนอนหลับน้อยกว่า 1 วินาทีให้ใช้ Sleep API ใน kernel32
Andrew Dennison

1
@ ZX9 timevalue ("00:00:01") = 0.0000115740 ... ดังนั้น Application.wait (ตอนนี้ + 0.00001) เป็นเวลาประมาณหนึ่งวินาที ฉันชอบใช้Application.wait(now + 1e-5)เป็นครั้งที่สองเป็นApplication.wait(now + 0.5e-5)เวลาครึ่งวินาทีเป็นต้น
Some_Guy

61

เพิ่มสิ่งนี้ลงในโมดูลของคุณ

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?
Ben S

10
ฉันใช้วิธีนี้เนื่องจากเป็นแบบพกพาระหว่างผลิตภัณฑ์สำนักงานต่างๆเช่น Access และไม่ใช่เฉพาะของ Excel
Buggabill

นอกจากนี้ยังมีแอปพลิเคชัน VBA (ERS) อีกตัวที่ฉันใช้ซึ่งมีภาษาย่อยที่ จำกัดมาก
Buggabill

18
+1 เนื่องจากSleep()ช่วยให้คุณระบุเวลารอน้อยกว่า 1 วินาที Application.Waitบางครั้งก็ละเอียดเกินไป
BradC

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

42

แทนที่จะใช้:

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

ฉันชอบ:

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

เพราะหลังจากนั้นอ่านง่ายขึ้นมาก


7
และใช้งานได้ในขณะที่ใน Office 2013 รูปแบบ # 0: 0: 1 # จะแปลงเป็น 1 วินาทีหลังเที่ยงคืน
Julian Knight

1
คำเตือน: โซลูชันทั้งหมดที่ใช้ 'Application.Wait' มีความไม่แม่นยำ 1 วินาที วิธีนี้ไม่พิจารณามิลลิวินาทีที่ผ่านไปแล้วนับตั้งแต่วินาทีปัจจุบันเริ่มต้นขึ้น ... ตัวอย่างเช่นหากเหลือเวลาเพียง 1 มิลลิวินาทีจนกว่าเวลาจะเปลี่ยนไปคุณจะเข้าสู่โหมดสลีปเพียง 1 มิลลิวินาทีเท่านั้น คุณแค่เปรียบเทียบตัวเลข 2 ตัวแทนที่จะรอ 1 วินาที!
cyberponk

18

มันทำงานได้อย่างไม่มีที่ติสำหรับฉัน แทรกโค้ดใด ๆ ก่อนหรือหลังลูป "do until" ในกรณีของคุณให้ใส่ 5 บรรทัด (time1 = & time2 = & "do until" loop) ต่อท้ายใน do loop

sub whatever()
Dim time1, time2

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

End sub

2
ฉันชอบวิธีแก้ปัญหานี้มากที่สุดเพราะฉันไม่ต้องการหยุดคิวข้อความ
Daniel Fuchs

โซลูชันนี้มีความแม่นยำและไม่จำเป็นต้องมีการประกาศ sleep-API-Function ฉันเคยเก็บเวลาเป็นค่าสองเท่าและใช้ไมโครวินาทีแทนด้วยผลลัพธ์เดียวกัน
DrMarbuse

โซลูชันนี้ทำงานได้ดีกว่าโซลูชันที่คล้ายกันด้านล่างที่ใช้Timerเนื่องจากTimerวิธีนี้ล้มเหลวก่อนเที่ยงคืน
vknowles

1
วิธีการแก้ปัญหานี้ไม่แม่นยำไม่คำนึงถึงมิลลิวินาทีที่ล่วงเลยไปแล้วจากเวลาปัจจุบัน ... ตัวอย่างเช่นหากเหลือเพียง 1 มิลลิวินาทีจนกว่าวินาทีนี้จะเปลี่ยนไปคุณจะเข้าสู่โหมดสลีปเพียง 1 มิลลิวินาทีเท่านั้น
cyberponk

เมื่อโซลูชันอื่นใช้เวลานานสำหรับแมโคร VBA ที่ไม่ใช่ MS Office อันนี้ก็ทำงานได้อย่างสมบูรณ์ - ขอบคุณ!
อยากรู้อยากเห็น

12

การประกาศสำหรับ Sleep ใน kernel32.dll จะไม่ทำงานใน Excel 64 บิต นี่จะเป็นการทั่วไปเล็กน้อย:

#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 ดูเหมือนจะไม่สนใจคำสั่งคอมไพเลอร์
Julian Knight

2
รวบรวมได้ดีสำหรับฉันใน Office 2013
Jon Peltier

คนส่วนใหญ่ยอมรับว่า Win64 / VBA7 dwMilliseconds นั้นยาวไม่ใช่ LongPtr Excel VBA ซ่อนข้อผิดพลาดเช่นนี้โดยทำการแก้ไขสแต็กหลังจากการโทรภายนอก แต่ข้อผิดพลาดเช่นนี้จะทำให้ Open Office เวอร์ชันส่วนใหญ่ผิดพลาด
david

6

เพียงแค่รหัสของ clemo เวอร์ชันที่ล้างแล้ว - ใช้งานได้ใน Access ซึ่งไม่มีแอปพลิเคชันรอฟังก์ชั่น

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คือ> = 86,400) ในเวลาเที่ยงคืนTimerรีเซ็ตเป็น 0 และยังคงน้อยกว่าsngEndตลอดไป
vknowles

ปล. โค้ดจาก @clemo ด้านบนใช้งานได้ตลอดเวลา
vknowles

@vknowles สิ่งที่คุณพูดเป็นความจริงอย่างแน่นอน และยังสามารถชดเชยได้ด้วยวิธีการด้านล่าง เนื่องจากวิธีนี้จัดการกับมิลลิวินาทีฉันจึงคิดว่าเป็นการเดิมพันที่ปลอดภัย `` Public Sub Sleep (sngSecs As Single) Dim sngEnd As Single sngEnd = Timer + (sngSecs / 1000) While Timer <sngEnd DoEvents If (sngEnd - Timer)> 50000 แล้ว sngEnd = sngEnd - 86400 End If Wend End Sub '' `
PravyNandas

5

ส่วนใหญ่ของการแก้ปัญหาที่นำเสนอใช้ Application.Wait ซึ่งไม่ได้ใช้ในบัญชีของเวลา (หน่วยเป็นมิลลิวินาที) ผ่านไปแล้วตั้งแต่ currend ที่สองนับเริ่มต้นเพื่อพวกเขามีความไม่แน่ชัดที่แท้จริงของถึง 1 วินาที

วิธีตั้งเวลาเป็นทางออกที่ดีที่สุดแต่คุณต้องคำนึงถึงการรีเซ็ตในเวลาเที่ยงคืนดังนั้นนี่คือวิธีการนอนหลับที่แม่นยำมากโดยใช้ตัวตั้งเวลา:

'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

3

Application.Wait Second(Now) + 1


คำเตือน: โซลูชันทั้งหมดที่ใช้ 'Application.Wait' มีความไม่แม่นยำ 1 วินาที วิธีนี้ไม่พิจารณามิลลิวินาทีที่ผ่านไปแล้วนับตั้งแต่วินาทีปัจจุบันเริ่มต้นขึ้น ... ตัวอย่างเช่นหากเหลือเวลาเพียง 1 มิลลิวินาทีจนกว่าเวลาจะเปลี่ยนไปคุณจะเข้าสู่โหมดสลีปเพียง 1 มิลลิวินาทีเท่านั้น คุณแค่เปรียบเทียบตัวเลข 2 ตัวแทนที่จะรอ 1 วินาที!
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
คำเตือน: โซลูชันทั้งหมดที่ใช้ 'Application.Wait' มีความไม่แม่นยำ 1 วินาที วิธีนี้ไม่พิจารณามิลลิวินาทีที่ผ่านไปแล้วนับตั้งแต่วินาทีปัจจุบันเริ่มต้นขึ้น ... ตัวอย่างเช่นหากเหลือเวลาเพียง 1 มิลลิวินาทีจนกว่าเวลาจะเปลี่ยนไปคุณจะเข้าสู่โหมดสลีปเพียง 1 มิลลิวินาทีเท่านั้น คุณแค่เปรียบเทียบตัวเลข 2 ตัวแทนที่จะรอ 1 วินาที!
cyberponk

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

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

คำเตือน: โซลูชันทั้งหมดที่ใช้ 'Application.Wait' มีความไม่แม่นยำ 1 วินาที วิธีนี้ไม่พิจารณามิลลิวินาทีที่ผ่านไปแล้วนับตั้งแต่วินาทีปัจจุบันเริ่มต้นขึ้น ... ตัวอย่างเช่นหากเหลือเวลาเพียง 1 มิลลิวินาทีจนกว่าเวลาจะเปลี่ยนไปคุณจะเข้าสู่โหมดสลีปเพียง 1 มิลลิวินาทีเท่านั้น คุณแค่เปรียบเทียบตัวเลข 2 ตัวแทนที่จะรอ 1 วินาที!
cyberponk

1

ฉันมักจะใช้ฟังก์ชันTimerเพื่อหยุดแอปพลิเคชันชั่วคราว ใส่รหัสนี้ให้กับคุณ

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

3
หากTimerให้จำนวนวินาทีนับตั้งแต่เที่ยงคืนวิธีนี้จะล้มเหลวหากดำเนินการก่อนเที่ยงคืน (กล่าวT0คือน้อยกว่าจำนวนวินาทีที่ล่าช้าจากเที่ยงคืน) เวลาเที่ยงคืนTimerรีเซ็ตเป็น 0 ก่อนถึงขีด จำกัด การหน่วงเวลา Delayไม่ถึงขีด จำกัด การหน่วงเวลาดังนั้นลูปจึงทำงานตลอดไป
vknowles

เนื่องจาก Timer สร้างค่าที่ไม่ใช่จำนวนเต็มคุณจึงควรใช้ Loop Until Delay >= 1หรือคุณเสี่ยงที่จะเกิน 1 และไม่ออกจากลูป
Jon Peltier

1

ฟังก์ชัน Wait and Sleep จะล็อก Excel และคุณไม่สามารถทำอะไรได้อีกจนกว่าการหน่วงเวลาจะเสร็จสิ้น ในทางกลับกันความล่าช้าของลูปไม่ได้ให้เวลาที่แน่นอนในการรอ

ดังนั้นฉันได้ทำการแก้ปัญหานี้เพื่อเชื่อมโยงกับแนวคิดทั้งสองเล็กน้อย มันวนซ้ำจนกว่าจะถึงเวลาที่คุณต้องการ

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

คุณเพียงแค่โทรไปที่ Waste10Sec เมื่อคุณต้องการความล่าช้า



โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.