Làm thế nào để tạm dừng trong khoảng thời gian cụ thể? (Excel / VBA)


103

Tôi có một trang tính Excel có macro sau. Tôi muốn lặp lại nó mỗi giây nhưng bị treo nếu tôi có thể tìm thấy hàm để làm điều đó. Không thể nào?

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

Loop
End Sub

Câu trả lời:


128

Sử dụng phương pháp Chờ :

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

hoặc (đối với Excel 2010 trở lên):

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

Tôi không chính xác ý của bạn là gì, nhưng tôi đoán bạn muốn DoEventsnhư được giới thiệu ở đây dailydoseofexcel.com/archives/2005/06/14/stopwatch
Ryan Shannon

3
@Benoit và @Keng, bạn có thể đặt trực tiếp 1 giây, tránh chuyển đổi văn bản cho đến nay. Sạch sẽ hơn đối với tôi: Application.Wait(Now + #0:00:01#)Cheers!
A.Sommerh

29
Định dạng mà không hoạt động trong Excel 2010. này hoạt động mặc dù:Application.Wait (Now + TimeValue("0:00:01"))
ZX9

1
DateAdd ("s", 1, Now) làm đúng. Và có thể được khái quát hóa cho bất kỳ số giây dài nào: DateAdd ("s", nSec, Now) mà không cần sử dụng chữ thời gian. Ngủ ít hơn 1 giây sử dụng API Ngủ trong kernel32
Andrew Dennison

1
Giá trị thời gian @ ZX9 ("00:00:01") = 0,0000115740 ... Vì vậy, Application.wait (hiện tại + 0,00001) là khoảng một giây. Tôi thích sử dụng Application.wait(now + 1e-5)trong một giây, Application.wait(now + 0.5e-5)trong nửa giây, v.v.
Some_Guy

61

Thêm cái này vào mô-đun của bạn

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

Hoặc, đối với hệ thống 64 bit, sử dụng:

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

Gọi nó trong macro của bạn như vậy:

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

Loop
End Sub

1
Tại sao không sử dụng phương pháp VBA để thực hiện việc này thay vì sử dụng kernel32.dll?
Ben S

10
Tôi đã sử dụng phương pháp này vì nó có thể di động giữa các sản phẩm văn phòng khác nhau như Access và không dành riêng cho Excel.
Buggabill

Ngoài ra còn có một ứng dụng VBA (ERS) khác mà tôi sử dụng có một tập hợp con ngôn ngữ rất hạn chế.
Buggabill

18
+1, vì Sleep()cho phép bạn chỉ định thời gian chờ dưới 1 giây. Application.Waitđôi khi quá hạt.
BradC

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

42

thay vì sử dụng:

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

tôi thích:

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

vì nó dễ đọc hơn rất nhiều sau đó.


7
Và nó hoạt động trong khi, trong Office 2013, định dạng # 0: 0: 1 # chuyển đổi thành 1 giây sau nửa đêm.
Julian Knight

1
CẢNH BÁO: Tất cả các giải pháp sử dụng 'Application.Wait' đều có 1 giây không chính xác. Phương pháp này không xem xét phần nghìn giây đã trôi qua kể từ khi giây hiện tại bắt đầu ... Ví dụ, nếu chỉ còn 1 phần nghìn giây cho đến khi giây thời gian thay đổi, bạn sẽ chỉ ngủ trong 1 phần nghìn giây. Bạn chỉ đang so sánh 2 số được làm tròn thay vì đợi 1 giây!
cyberponk

18

điều này hoạt động hoàn hảo đối với tôi. chèn bất kỳ mã nào trước hoặc sau vòng lặp "làm cho đến khi". Trong trường hợp của bạn, hãy đặt 5 dòng (time1 = & time2 = & "do until") ở cuối vòng lặp do của bạn

sub whatever()
Dim time1, time2

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

End sub

2
Tôi thích giải pháp này nhất vì tôi không muốn tạm dừng hàng đợi tin nhắn.
Daniel Fuchs

Giải pháp này chính xác và không yêu cầu khai báo hàm sleep-API-Function. Tôi đã từng lưu trữ thời gian ở các giá trị kép và thay vào đó sử dụng micro giây với cùng một kết quả.
DrMarbuse

Giải pháp này hoạt động tốt hơn các giải pháp tương tự bên dưới được sử dụng TimerTimercách tiếp cận không thành công ngay trước nửa đêm.
vknowles

1
Giải pháp này không chính xác, nó không tính đến mili giây đã trôi qua từ thời điểm hiện tại ... Ví dụ, nếu chỉ còn 1 mili giây nữa cho đến khi Giờ hiện hành thay đổi, bạn sẽ chỉ ngủ trong 1 mili giây.
cyberponk

khi các giải pháp khác mất nhiều thời gian cho macro VBA không dựa trên MS Office, giải pháp này hoạt động hoàn hảo - cảm ơn!
tò mò

12

Khai báo Sleep trong kernel32.dll sẽ không hoạt động trong Excel 64 bit. Điều này sẽ tổng quát hơn một chút:

#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
Không thể biên dịch trong Office 2013. Trình kiểm tra lỗi trong VBA cho Office 2013 dường như bỏ qua các câu lệnh trình biên dịch.
Julian Knight

2
Biên dịch tốt cho tôi trong Office 2013.
Jon Peltier

Hầu hết mọi người đều đồng ý rằng Win64 / VBA7 dwMilliseconds là Long, không phải LongPtr. Excel VBA giấu lỗi như thế này bằng cách thực hiện chỉnh stack sau khi cuộc gọi bên ngoài, nhưng lỗi như thế này sẽ sụp đổ hầu hết các phiên bản của Open Office
david

6

Chỉ là phiên bản mã của clemo đã được làm sạch - hoạt động trong Access, không có chức năng 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
Nếu Timercung cấp số giây kể từ nửa đêm, thì cách tiếp cận này không thành công nếu nó được thực hiện ngay trước nửa đêm (tức sngEndlà> = 86.400). Vào lúc nửa đêm, Timerđặt lại về 0 và do đó, vẫn ít hơn sngEndmãi mãi.
vknowles

PS Mã từ @clemo ở trên hoạt động bất kỳ lúc nào trong ngày.
vknowles

@vknowles, những gì bạn nói là hoàn toàn đúng. Và cũng có thể được bồi thường trong phương pháp dưới đây. Vì phương pháp này xử lý mili giây, tôi nghĩ đó là một đặt cược an toàn. `` 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

Hầu hết các giải pháp được trình bày đều sử dụng Application.Wait, không tính đến thời gian (mili giây) đã trôi qua kể từ khi bắt đầu đếm giây của dòng điện, vì vậy chúng có độ chính xác nội tại lên đến 1 giây .

Cách tiếp cận Bộ hẹn giờ là giải pháp tốt nhất , nhưng bạn phải tính đến việc đặt lại vào lúc nửa đêm, vì vậy đây là một phương pháp Ngủ rất chính xác bằng Bộ hẹn giờ:

'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

SỬ DỤNG NÀY ĐỂ KIỂM TRA BẤT KỲ CHỨC NĂNG NGỦ NÀO: (mở cửa sổ gỡ lỗi ngay lập tức: 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


CẢNH BÁO: Tất cả các giải pháp sử dụng 'Application.Wait' đều có 1 giây không chính xác. Phương pháp này không xem xét phần nghìn giây đã trôi qua kể từ khi giây hiện tại bắt đầu ... Ví dụ, nếu chỉ còn 1 phần nghìn giây cho đến khi giây thời gian thay đổi, bạn sẽ chỉ ngủ trong 1 phần nghìn giây. Bạn chỉ đang so sánh 2 số được làm tròn thay vì đợi 1 giây!
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
CẢNH BÁO: Tất cả các giải pháp sử dụng 'Application.Wait' đều có 1 giây không chính xác. Phương pháp này không xem xét phần nghìn giây đã trôi qua kể từ khi giây hiện tại bắt đầu ... Ví dụ, nếu chỉ còn 1 phần nghìn giây cho đến khi giây thời gian thay đổi, bạn sẽ chỉ ngủ trong 1 phần nghìn giây. Bạn chỉ đang so sánh 2 số được làm tròn thay vì đợi 1 giây!
cyberponk

2

Đây là một giải pháp thay thế cho giấc ngủ:

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

Trong đoạn mã sau, tôi tạo hiệu ứng "phát sáng" nhấp nháy trên nút xoay để hướng người dùng đến nó nếu họ "gặp sự cố", sử dụng "sleep 1000" trong vòng lặp dẫn đến không nhìn thấy nhấp nháy, nhưng vòng lặp hoạt động rất tốt.

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

tôi đã làm điều này để trả lời vấn đề:

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

CẢNH BÁO: Tất cả các giải pháp sử dụng 'Application.Wait' đều có 1 giây không chính xác. Phương pháp này không xem xét phần nghìn giây đã trôi qua kể từ khi giây hiện tại bắt đầu ... Ví dụ, nếu chỉ còn 1 phần nghìn giây cho đến khi giây thời gian thay đổi, bạn sẽ chỉ ngủ trong 1 phần nghìn giây. Bạn chỉ đang so sánh 2 số được làm tròn thay vì đợi 1 giây!
cyberponk

1

Tôi thường sử dụng chức năng Hẹn giờ để tạm dừng ứng dụng. Chèn mã này vào mã của bạn

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

3
Nếu Timercung cấp số giây kể từ nửa đêm, thì cách tiếp cận này không thành công nếu nó được thực hiện ngay trước nửa đêm (tức T0là ít hơn số giây trễ từ nửa đêm). Vào lúc nửa đêm, Timerđặt lại về 0 trước khi đạt đến giới hạn độ trễ. Delaykhông bao giờ đạt đến giới hạn trễ, vì vậy vòng lặp chạy mãi mãi.
vknowles

Vì Timer tạo ra các giá trị không phải là số nguyên, bạn nên sử dụng Loop Until Delay >= 1, nếu không bạn có nguy cơ vượt quá 1 và không bao giờ thoát khỏi vòng lặp.
Jon Peltier,

1

Các hàm Wait and Sleep khóa Excel và bạn không thể làm gì khác cho đến khi hết thời gian trễ. Mặt khác, sự chậm trễ của vòng lặp không cho bạn thời gian chính xác để chờ đợi.

Vì vậy, tôi đã thực hiện cách giải quyết này để kết hợp một chút của cả hai khái niệm. Nó lặp lại cho đến khi thời gian bạn muốn.

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

Bạn chỉ cần gọi đến Waste10Sec khi bạn cần sự chậm trễ


0

Thử cái này :

Threading.thread.sleep(1000)

0

Bạn có thể sử dụng Application.wait now + timevalue ("00:00:01") hoặc Application.wait now + timeerial (0,0,1)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.