VBで、ある時間プログラムの進行を止めたいです。
下記のコードだとCPU使用率が100%になってしまいます。
ほかに、方法は無いのでしょうか?
Dim Now As Long
Now = Timer
While Timer < Now +10 '10秒間待機する
DoEvents
Wend
Beep '終了した事を教える
# VB6 なのですね。
そもそも、「ループでの待機処理」を行うべきではありません。
提示されたコードでは、その他にも、
・変数名 Now は、Now 関数と競合する名前なので、避けるべきです。
・Timer 関数の戻り値は、Long 型では無い点に注意してください。
・10 秒後の値を得るには、DataAdd 関数を使いましょう。
・DoEvents は、イベント再入などの弊害を持つので、極力避けましょう。
といった問題があります。
> ほかに、方法は無いのでしょうか?
Timer コントロールを利用しましょう。
Private Sub Command1_Click()
Timer1.Interval = 10000 '10秒
Timer1.Enabled = True '開始
End Sub
Private Sub Timer1_Timer()
Timer1.Enabled = False
MsgBox "10秒経ちました。", vbInformation
End Sub
VB のコードは、「イベント」ベースで行われるべきです。
たとえば、チェックボックスの On/Off が行われた時に処理したいなら、
Do
DoEvents
If Check1.Value = vbChecked Then
Label1.Caption = "On 状態"
Else
Label1.Caption = "Off 状態"
End If
Loop
のようにループで監視したりはせず、
Private Sub Check1_Click()
If Check1.Value = vbChecked Then
Label1.Caption = "On 状態"
Else
Label1.Caption = "Off 状態"
End If
End Sub
のように、イベントを用いて処理しますよね。
魔界の仮面弁士さん、とても解りやすい指導ありがとうございます。
フォームで作業しながら、見えないところでWebbrowserで巡回しています。
フォームから、タイマーのイベントをtrueにして
Timer1のイベントを発生 そこで、for文で、サイトを巡回します。
Private Sub Timer1_Timer()
Timer1.enabled = false
for i = 0 to x
Wb.Navigate(address(x))
'ここで10秒待ちたい
wb.Document.links(0).click
'ここで10秒待ちたい
next i
End Sub
'ここで10秒待ちたい の所に、
検索したループ文で10秒待機しましたが、よくないです。
sleepも駄目。
タイマーを使うと、その先までコードが走ってしまいます。
どうすれば、良いのでしょうか?
タイマーを使用すれば、10秒待って次のイベントを呼び出すことは難しくは無いが、
ループの一番最後の2番目のイベントを呼び出して、CPUの使用率を上げずに
Sleepも使わずに10秒間待つのは難しい............
最後のイベントが終了して待つ必要が無ければ、
Const SEC = 1000
Dim intNo As Integer
Private Sub Command1_Click()
Timer1.Enabled = False
Timer1.Interval = 10 * SEC
intNo = 1
DoWork
Timer1.Enabled = True
End Sub
Private Sub Timer1_Timer()
Timer1.Enabled = False
intNo = intNo + 1
DoWork
If intNo / 2 < 10 Then
Timer1.Enabled = True
End If
End Sub
'//何かの処理
Private Sub DoWork()
If intNo Mod 2 <> 0 Then
Debug.Print "処理:" & (intNo \ 2) + 1 & "-A"
Else
Debug.Print "処理:" & (intNo \ 2) & "-B"
End If
End Sub
こんな手はある。
ただこんなに苦労しなくても
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function timeGetTime Lib "winmm.dll" () As Long
'待ち時間を1/1000秒で指定
Private Sub timeWait(timeWait As Integer)
Dim timeStart As Long
timeStart = timeGetTime
Dim count As Integer
Do
count = count + 1
If count > 1000 Then
count = 0
Sleep (1)
DoEvents
End If
Loop While (timeGetTime <= timeStart + timeWait)
End Sub
こんな関数を一つ作っておけば案外上手くいくかも、CPUの使用率も上がらない。
魔界の仮面弁士さんの書かれた,
>> そもそも、「ループでの待機処理」を行うべきではありません。
と
>> VB のコードは、「イベント」ベースで行われるべきです。
が全てだとおもうのですが。
状態の遷移で考えるようにしてみると,どうすればよいのかわかりやすくなると思います。
「待つ」行為は,「指定時間が経ったら状態が遷移する」のですから,タイマーで十分状態遷移させられます。
> タイマーを使うと、その先までコードが走ってしまいます。
最初の時間待ちは,実はNavigateComplete2イベントを使うべき,ということはありませんか?
> Wb.Navigate(address(x))
> 'ここで10秒待ちたい
> wb.Document.links(0).click
その処理が、そもそもの間違いであるようにも思えます。
本来は「10秒間待機する」のではなく、ページの読込完後に行うべきなので
リンクのクリック処理を、DocumentComplete イベントに移動しましょう。
ちなみに、NavigateComplete2 は、ページ遷移後に発生するイベント、
DocumentComplete は、HTMLDocument の解析後に発生するイベントです。
Document プロパティへのアクセスを目的とするのであれば、
DocumentComplete イベントの方を使ってみてください。
# フレームを切っている場合、フレーム単位でイベントが発生するので注意。
また、Sleep & DoEvents 法も避けるかと思われます。
VB4 当時の補足ヘルプファイル等で紹介されていた事もあって、未だに
使われている現場を見かけますが、本来 DoEvents する必要が無い時にまで
呼び出される事もあって、イベントよりも負荷率は上です。
そのため、MsgWaitForMultipleObjects を使う、SetWaitableTimer を
併用したりして回避するという手もありますが…標準のイベント処理で
十分に回避できる場合においては、API に頼らず実装した方が安全でしょう。
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200510/05100129.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200706/07060026.txt
http://support.microsoft.com/kb/231298/ja
DocumentComplete を使う方法も知っていますが、
サクサク、リンク移動をしたくないのです。
10秒間隔くらいで推移したい目的があるので
書かれた事をもとに、ロジックを考えて見ます。
ツイート | ![]() |