特定の時間だけ一時停止するには?(Excel / VBA)


103

次のマクロを含むExcelワークシートがあります。私は毎秒ループしたいのですが、それを行う関数を見つけることができればダンジします。できませんか?

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

Loop
End Sub

回答:


128

Waitメソッドを使用します。

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

または(Excel 2010以降の場合):

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

それが何を意味するのかは正確にはわかりませんがDoEvents、ここで毎日
ライアンシャノン

3
@Benoitと@Kengの場合、テキストを日付に変換せずに、1秒を直接入力できます。私にとってよりきれいです: Application.Wait(Now + #0:00:01#)乾杯!
A.Sommerh 2014

29
その形式は、エクセル2010で働いていませんでしたこれは動作しますけれども:Application.Wait (Now + TimeValue("0:00:01"))
ZX9

1
DateAdd( "s"、1、Now)は正しいことを行います。また、時間リテラルを使用せずに、任意の長い秒数で一般化できます。DateAdd( "s"、nSec、Now)。1秒未満でスリープするには、kernel32でスリープAPIを使用します
Andrew Dennison

1
@ ZX9 timevalue( "00:00:01")= 0.0000115740 ...したがって、Application.wait(now + 0.00001)は約1秒です。私が使用したいApplication.wait(now + 1e-5)、秒間Application.wait(now + 0.5e-5)0.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
kernel32.dllを使用するのではなく、VBAメソッドを使用してこれを実行しないのはなぜですか?
ベンS

10
この方法は、Accessなどのさまざまなオフィス製品間で移植可能で、Excel固有ではないため、使用しました。
バガビル2009年

言語のサブセットが非常に限られている、私が使用する別のVBAアプリケーション(ERS)もあります。
バガビル

18
+1、1 Sleep()秒未満の待機時間を指定できるため。Application.Wait時々細かすぎます。
BradC 2010年

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秒後に変換されるのに対し、これは機能します。
ジュリアンナイト

1
警告:「Application.Wait」を使用するすべてのソリューションは1秒の不正確さを持っています。この方法では、現在の秒が開始してから既に経過したミリ秒は考慮されません...たとえば、時間の秒が変わるまで1ミリ秒しか残っていない場合、1ミリ秒だけスリープします。1秒待つのではなく、2つの丸められた数値を比較しているだけです。
cyberponk

18

これは完璧に機能します。「do until」ループの前または後にコードを挿入します。あなたのケースでは、5行(time1 =&time2 =& "do until"ループ)をdoループ内の最後に置きます

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 2017

1
このソリューションは正確ではありません。現在の時刻から既に経過したミリ秒は考慮されません...たとえば、Now秒が変更されるまで1ミリ秒しか残っていない場合、1ミリ秒だけスリープします。
cyberponk

他のソリューションが非MS OfficeベースのVBAマクロに長い時間かかっていた場合、これは完全に機能しました-ありがとう!
好奇心が強い

12

kernel32.dllでのスリープの宣言は、64ビットのExcelでは機能しません。これはもう少し一般的です:

#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でコンパイルできません。Office2013のVBAのエラーチェッカーは、コンパイラーステートメントを無視しているようです。
ジュリアンナイト

2
オフィス2013での私のためにコンパイルの罰金
ジョンペルチェ

ほとんどの人は、Win64 / VBA7のdwMillisecondsがLongPtrではなくLongであることを認めています。Excel VBAは、外部呼び出しの後にスタック修正を行うことでこのようなエラーを隠しますが、このようなエラーはOpen Officeのほとんどのバージョンをクラッシュさせます
david

6

クリーンアップされたクレモのコードのバージョン-Application.Wait関数を持たない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午前0時からの秒数を指定する場合、午前0時の直前に実行すると(つまり、sngEnd86,400以上)、このアプローチは失敗します。真夜中に、0にTimerリセットされるため、sngEnd永久に残ることはありません。
vknowles 2017

PS上記の@clemoのコードは、いつでも機能します。
vknowles 2017

@vknowles、あなたが言ったことは絶対に本当です。また、以下の方法で補正することもできます。このメソッドはミリ秒を処理するので、安全な方法だと思います。`` `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

提示されたソリューションのほとんどはApplication.Waitを使用します。これは、現在の秒数のカウントが開始されてから既に経過した時間(ミリ秒)を考慮しないため、本質的に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ミリ秒だけスリープします。1秒待つのではなく、2つの丸められた数値を比較しているだけです。
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ミリ秒だけスリープします。1秒待つのではなく、2つの丸められた数値を比較しているだけです。
cyberponk

2

ここに睡眠の代替があります:

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

次のコードでは、ユーザーが「問題を抱えている」場合にスピンボタンを「グロー」効果で点滅させて、ユーザーにその効果を伝えています。ループで「スリープ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ミリ秒だけスリープします。1秒待つのではなく、2つの丸められた数値を比較しているだけです。
cyberponk

1

通常、タイマー機能を使用してアプリケーションを一時停止します。このコードをあなたのものに挿入してください

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

3
Timer午前0時からの秒数を指定する場合、午前0時の直前に実行すると(つまり、T0午前0時からの遅延秒数よりも少ない場合)、このアプローチは失敗します。午前0時に、Timer遅延制限に達する前に0にリセットされます。Delay遅延制限に到達しないため、ループは永久に実行されます。
vknowles 2017

Timerは非整数値を生成するので、を使用する必要がLoop Until Delay >= 1あります。そうしないと、1を超えてループを終了するリスクがなくなります。
Jon Peltier

1

待機およびスリープ機能はExcelをロックし、遅延が終了するまで他に何もできません。一方、ループの遅延では、待機する正確な時間がわかりません。

だから、私はこの回避策を両方の概念の少しに参加させました。時間はあなたが望む時間になるまでループします。

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

遅延が必要な場所でWaste10Secを呼び出すだけです


0

これを試して :

Threading.thread.sleep(1000)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.