VisualBasic(脳トレ的アプリ006: ProgressBarのずれ)
■問題を回答する時間について検討してみる。
前回までで問題作成部分についてはできた。今回は、問題を回答する時間について考えてみる。
前回挙げた動画の通り、今のコードは1秒ごとにProgressBarを進め、10秒に達したら終了する形になっている。コードは、TimerとProgressBarを使った下のような感じ。
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
ProgressBar1.PerformStep()
If ProgressBar1.Value = ProgressBar1.Maximum Then
Dispose()
End If
End Sub
Timer1_Tickは、指定した間隔(Interval)ごとに中のコードを実行。ProgressBar1.PerformStep()は、指定したStepだけバーを進める。ProgressBarやTimerは、Visual Studioから追加したりプロパティ変更したりできる(下の図は、Timer1のInterval = 1000ミリ秒)。ProgressBarは、Step = 10, Maximum = 100としている。
そのため、上のコードは1秒ごとに10だけバーを進め、100になった時点で終了となる。
バーが100になった時点ですぐ終了するが、ProgressBar1.PerformStep()で数値が更新されるタイミングと画面上でバーが進むタイミングに少しラグがあるらしく、見た目上、バーが最後まで行く前に終了してしまう。
Timerの設定を1000ミリ秒から10ミリ秒ごとにし、ProgressBarのStep, Maximumをそれぞれ1, 1000にすれば、同じ10秒でも、上では10回のコードの実行に対して1000回の実行となる。バーの進み方が滑らかになるけど、最後まで行く前に終了するのは変わらない。
終了前に少し待つコードなど入れればいいのかな?と思い、Thread.Sleepを入れてみる。
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
ProgressBar1.PerformStep()
If ProgressBar1.Value = ProgressBar1.Maximum Then
System.Threading.Thread.Sleep(1000)
Dispose()
End If
End Sub
しかし、これで停止させると、バーを進める部分も停止してしまうよう。
次に、Task.Delayでの停止を考えてみた。下のようにAsync, Awaitで処理すると、バーを進める部分の停止はせず、待つことができた。ただ、終わりの判定は、バーが最後まで行く前にされてしまう。
数値が最後まで行ったとき(ProgressBar1.Value = ProgressBar1.Maximum)をデバックで見てみると、 やはりバー自体は最後まで行っていない(下の図)。
Private Async Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
ProgressBar1.PerformStep()
If ProgressBar1.Value = ProgressBar1.Maximum Then
Await Task.Delay(600)
End If
If ProgressBar1.Value = ProgressBar1.Maximum Then
Dispose()
End If
End Sub
いろいろと触ってみると、上のデバッグ時の状態でも、回答すれば次の問題に行きバーをリセットできた。
Timer, ProgressBarの設定とTask.Delayの値を調整して、見た感じバーが最後まで行ったら終了になるようにする。設定は、Timer interval = 1ミリ秒、ProgressBar Step = 1, Maximum = 200、Task.Delay(600)とした。何度か動かしてみて、10秒では長すぎるので、だいたい3,4秒くらいで終了になるようにした。
ProgressBarのずれについては、ネットでも似たような問題があるよう。何か定番の解決方法があるかもしれないけど、今回はここまで。