要件の実現方法
あまり使う場面はないと思われますが、今回のような要件があった場合、どうしたら良いでしょうか。色々試行錯誤した結果が、以降の記載になります。
スレッドは一本化では普通に処理が止まってしまうので、マルチスレッドとします。ということで、今回は「BackgroundWorker」を使用します。
ここで注意する点は、メインスレッドが「処理時間の表示」でバックグラウンドで「時間がかかる処理」をさせることです。なぜそうしたかは後で書きます。
まずはボタンイベントから書きます。
1 2 3 4 5 6 |
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Button1.Enabled = False BackgroundWorker1.RunWorkerAsync() hproc() Button1.Enabled = True End Sub |
ボタンイベントは、以下のような感じにしています。
- ボタンを無効
- バックグラウンドイベントを起動
- バックグラウンドが終わるまで待つためのメソッド
- ボタンを有効(処理が終わったことの確認)
ボタンの有効無効は、ボタンの連続押下で例外を発生させないために入れています。実用するなら中止ボタンなどを入れても良いかもしれません。
また、バックグラウンドのイベントには時間のかかる処理を記載します。 例として以下のようにしています。 この場合、処理に大体10秒前後かかります。
1 2 3 4 5 6 7 |
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork Dim ttt As Integer For i As Integer = 1 To 10000000 ttt = CInt("12345") Next blnEnd = True End Sub |
※終了時の「RunWorkerCompleted」や「ProgressChanged」イベントは今回は入れていません。
また、バックグラウンドが終わるまで待つためのメソッドとして以下のようにしています。
1 2 3 4 5 6 7 8 9 10 11 |
Private Sub hproc() Dim startDt = DateTime.Now While True System.Threading.Thread.Sleep(1000) Dim endDt As DateTime = DateTime.Now Dim ts As TimeSpan = endDt - startDt Label1.Text = ts.Seconds.ToString("00") Label1.Update() If blnEnd = True Then Exit While End While End Sub |
基本的にははじめにスタート時間を取得し、その後無限ループで待機します。(周期はThread.Sleepで1秒待機としています)
ループ中は、毎回現在の時間を取得し、開始時間との差をラベルに表示させます。また、Updateで表示を更新させます。
バックグラウンドの処理が終わると、終了フラグが立つので、それにより無限ループから出ます。終了フラグはクラス共通変数としてます。
1 |
Private blnEnd As Boolean = False |
これを動作させると、ボタンを押すと処理中は時間がリアルタイムに表示され、終了すると時間の表示が止まります。(ボタンを再度押すことでまた同じように0から時間がカウントされます。)
これで要件通りとなりました。
色々と試したができなかったこと
作成時にはメインスレッドでメイン処理を書いていて、後で今回のような処理時間の表示をつけようとすると、つい、バックグラウンドを追加して、処理時間の表示をさせようという形を取りがちですが、それではラベルは変わってくれませんでした。
バックグラウンドの通常の使い方は「ProgressBar」の表示などで使うため、ラベル表示でもいけると思いましたが、無理でした。
また、ここでは書いていませんが、ストップウォッチを使ったTimerはうまく使えませんでした。( TimerとLabelの更新イベントが溜まりすぎるのか、わからなかったですが)
とりあえず、上記したものについては、時間のかかる処理において「Application.DoEvents」を使えば、思い通りに動きます。
しかし、この 「Application.DoEvents」は、使用自体は推奨されていないみたいですね。※使う意図と処理が、明確ならば問題はないようですが…。
わかったこと
結局、なんとかなったもののイベントの溜まり状況がよくわからなかったため、スッキリはしていません。もっと勉強は必要ですね。
また、今回の要件ですが、インストールするときなどに時間がかかる場面で使うと良いかもしれないですが、一般のソフトでそういう機能があるものって、そんなに見たことはないですよね。(ゲームではよく見ますが…)
それだけ、リスクがあるということでしょうか。
コメント