PictureBoxを点滅させたい

タグの編集
投稿者 おせい  (学生) 投稿日時 2009/8/20 03:35:27
はじめまして。
VB.NETを使用しています。

Timerを使って、周期的にPictureBoxの色を変えたいと思っております。
そこで以下のようにプログラムを書いたのですが、色が一度変化したきり変化しません。

PictureBox1.BackColor = Color.GreenYellow
System.Threading.Thread.Sleep(200)
PictureBox1.BackColor = Color.Gold

なおウォッチ式でBackColor1の値を見ますと、GreenYellowとGoldに交互に変化はしているようです。

お手数ですが、どなたか色が変化しない原因を教えていただけないでしょうか。
宜しくお願い致します。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/8/20 06:26:38
画面を表示させているスレッドは、Sleep させてはいけません。
Sleep 中は、画面の再描画も行われませんし、ユーザー操作も受け付けなくなります。


周期的に処理を行いたい場合には、Timer クラスの Tick イベントで処理するようにしてみてください。
投稿者 (削除されました)  () 投稿日時 2009/8/20 18:42:11
(削除されました)
投稿者 (削除されました)  () 投稿日時 2009/8/26 00:19:30
(削除されました)
投稿者 おせい  (学生) 投稿日時 2009/8/26 00:22:52
>魔界の仮面弁士さん

ご回答ありがとうございます。
返信遅くなりまして申し訳ございません。

>Sleep 中は、画面の再描画も行われませんし、ユーザー操作も受け付けなくなります。

とのことですが、プロパティの値が変化しているのに、フォームに実際に反映されないということはスレッドがスリープ状態になっているからだということでしょうか?
今のところ、プログラムを起動すると(スリープ後)の一度目は色が変更しているのですが、これとスリープ状態というのは関係ないのでしょうか(GreenYellow→Gold)。
質問ばかりで申し訳ございません。お時間あるときにでも教えていただけますと助かります。
投稿者 太郎冠者  (社会人) 投稿日時 2009/8/26 01:25:07
>とのことですが、プロパティの値が変化しているのに、フォームに実際に反映されないということはスレッドがスリープ状態になっているからだということでしょうか?
違います。
フォームの外観が変化しないのは、BackColorプロパティを変更した後、変更された値での再描画が行われていないからです。
下記のようにすれば、一応タイトルの要件は満たすことができると思います。
PictureBox1.BackColor = Color.GreenYellow
PictureBox1.Refresh()   'PictureBox1を再描画させる 
System.Threading.Thread.Sleep(200)
PictureBox1.BackColor = Color.Gold


ただ、既に魔界の仮面弁士さんが言われてるように、これは良くないコーディングです。
Sleepは使わずにTimer.Tickイベントを使用して、例えば以下のように修正するといいです。
'TimerのIntervalを200に設定すれば200msごとに背景色が変化する 
Private Sub Timer1_Tick(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Timer1.Tick

    If PictureBox1.BackColor = Color.GreenYellow Then
        '背景色がGreenYellowならGoldに変更 
        PictureBox1.BackColor = Color.Gold

    Else
        '背景色がGreenYellowではないならGreenYellowに変更 
        PictureBox1.BackColor = Color.GreenYellow

    End If

End Sub


投稿者 るしぇ  (社会人) 投稿日時 2009/8/26 01:59:11
理論の方で補足します。

画面の描画処理もまたプログラムです。
プロパティの値を見てディスプレイ上に四角形を書くプログラム
だと思ってください。
そして、そのプログラムは自分で書かないだけで(Microsoftが書いて
くれてるだけで)自分でプログラミングした関数と同等と思ってください。

何か1つのプログラムが実行されている場合、CPU は1個ですので
実行される処理も1つです。
後から命令された処理(※ただしイベント起動のもの)は、実行できる
状態になるまで待機状態になります。

プログラムコードを基準に言えば、1つの関数内のコードは
1セットとして扱われ、関数を抜けるまでに他の処理の実行命令
(イベント)が起こった場合、待機状態になります。

>PictureBox1.BackColor = Color.GreenYellow
>System.Threading.Thread.Sleep(200)
>PictureBox1.BackColor = Color.Gold
これらを1つの関数(Timer.Tick イベント関数)内に書いて
あれば、Color.GreenYellow が画面に表示されることは無く、
Color.Gold になった後、関数を抜け、その後から実行される
再描画処理が、プロパティを確認し、Color.Gold で描画します。

この処理順に関しては Sleep が無くても同じです。
Sleep があっても描画処理が走る条件は満たしません。
・・・関数内の処理が実行中のままなのですから、当然
描画処理は待機状態のままになります。

このとき、別のプロセスがコンピュータ上で動いていた場合、
CPU を使ってない状態になるため、実行されます。
つまりこのプログラムと全く関係ないエクセルファイルを
開いていたとして、このプログラムのために CPU を100%
使っていて、エクセルファイルの表示処理にまで影響を与えて
いるような状態だった時、こちらのプログラムが Sleep
すると CPU に処理を実行する余裕ができます。すると
エクセルファイルで保留にされていた処理が実行される
場合はあります。

Sleep がどんな命令か調べたことありますか?
そこに書いてあった説明をどの程度理解していますか?
http://msdn.microsoft.com/ja-jp/library/cc429358.aspx
Sleep は「実行を中断」
つまり「自分のプログラムで何も処理しない」という
だけですよ。
投稿者 おせい  (学生) 投稿日時 2009/8/27 00:30:44
>るしぇさん

大変丁寧な説明ありがとうございます。
また修正案の方でプログラムを修正しましたところ、点滅することが確認できました。
ありがとうございます。

>これらを1つの関数(Timer.Tick イベント関数)内に書いて
>あれば、Color.GreenYellow が画面に表示されることは無く、
>Color.Gold になった後、関数を抜け、その後から実行される
>再描画処理が、プロパティを確認し、Color.Gold で描画します。

ではプロパティの値が変化しているだけで、Timer.Tick イベント関数
内での処理後に再描画処理が行われているから、色の変化が起こらない。
そして、そのためSleepがあってもなくても同じである。

と理解しましたが、これで正しいでしょうか。

>Sleep がどんな命令か調べたことありますか?
>そこに書いてあった説明をどの程度理解していますか?

申し訳ございません。Sleepについてきちんと調べておらず、理解もできていませんでした。
さっそく教えていただきましたリンク先を参照してみようと思います。
投稿者 (削除されました)  () 投稿日時 2009/8/30 01:51:02
(削除されました)