トップ回答者
VB2005でグラフ画像を裏-->表にすると真白になってしまいます。

質問
-
VB6からVB2005に最近乗り換えたばかりです。VB6で出来ていた事がVB2005で出来ずに悩んでいます。内容はLINE関数でグラフを掃引描画してオシロスコ-プのように波形を描かせています。これにPAUSE機能を追加して掃引を停止した状態で他のアプリ作業を行ないます。当然アプリ作業画面がアクティブ(表)となり掃引画面は(裏)となります。アプリ作業が終了して再度掃引画面が(表)となった時VB6では自動的に以前の掃引画面が復元して問題ありません。しかしVB2005では(裏)となっていた部分が真っ白になったままで復元が出来ません。これをVB6と同じように自動で復元できるように設定する方法があるのでしょうか? よろしくお願いします。
回答
-
Ao55 さん、こんにちは
ダッチです。グラフの描画は何に対して(Form? PictureBox?)、どのタイミング(Paint イベント? OnPaint メソッド?)で行っているのでしょうか。
おそらくボタンをクリックした時に CreateGraphics メソッドを使用して描画しているのではないかと推測して話を進めさせていただきます。このやり方では 掃引画面 に再描画が必要になった時に描画していないため、描画していた内容が消えてしまいます。再描画が必要になったときに描画してやるだけで問題は解決されると思います。
再描画が必要になったときに描画するにはいろいろとやり方があります。
- Paint イベントで描画する
- OnPaint メソッドで描画する
- Image プロパティ(PictureBox の場合)に画像を設定する
参考になる記事がありますので紹介します。
PictureBoxのImageプロパティに関するよくある勘違い
http://dobon.net/vb/dotnet/graphics/pictureboximageanddrawimage.htmlPictureBoxコントロールにグラフィックを描画するには?
http://www.atmarkit.co.jp/fdotnet/dotnettips/458picboxdraw/picboxdraw.html
- Paint イベントで描画する
-
外池と申します。
Ao55さんが遭遇されている問題が、VB6と、VB.NETの一番ギャップの激しいところだと思います。ご苦労が多いと思いますが、頑張ってください。
ダッチさんのご説明にもありますが、要するに、.NETの場合ですと、
-
画面に描いた絵は、まったく「一時的なもの」であること、
-
したがって、自作のアプリの上に、別のアプリのウィンドウを移動してきて隠す、そして、別のアプリのウィンドウを取り除くと、もとの絵が現れることはなく、壊れたままになります。(真っ白だったり、別のアプリの絵が残っていたり)
-
したがって、再度正しく描き直す操作を自作アプリで面倒をみてやらないといけません。描き直すことが必要なタイミングだけは、Windows側から知らせてくれるようになっています。それが、OnPaintというイベントです。
このことをご理解頂いたうえで、じゃぁ、描き直す方法はどうあるべきか? ということになります。
- 画像が、点と線で表現されるもので、点の座標や結ぶ線の色や太さなどの情報がすべて揃っているのであれば、OnPaintの度に、線画で結んでいく要領で描き直すようにできます。表示する画面のサイズが変更された場合に再描画する時でも柔軟に対応ができます。
- 一方で、ビットマップ画像として、自作アプリ内に時々刻々の波形を保管しておくこともできます。で、OnPainのイベントが発生すれば、このビットマップ画像を表示する命令だけを実行すればOKです。VB6時代とほぼ同じ要領のプログラミングが行えます。
もちろん、OnPaintが発生しなくても、自作アプリで次々と新しいデータが入ってきて画面を更新しないといけません。その場合、自作アプリから要求してOnPaintを発生させるわけですが、それが、Refreshメソッドであったり、Invalidateメソッドだったりします。
-
-
外池です。
PAUSEというのは、アプリ自身の動作ですよね・・・。
他アプリが絡んでこないのであれば、お知らせ頂いた方法でOKだと思います。
意地悪な指摘で恐縮なのですが、掃引描画中に他アプリのウィンドウが覆いかぶさって来て、他アプリの作業が終わったら取り除かれる事態は想定されていますでしょうか? 本アプリ自体を最小化して一度消えて、再び表示するようなことも・・・。
今のままだと・・・、ひとつ前のPAUSE画面が再度現れて、そこに現在進行中の掃引状況が重ね書きされるようなことになるのではないかと危惧します。
私のお奨めとしましては、時々刻々の掃引を、_bmpに描き、そのたびに、Me.InvalidateをすればOKかと。
老婆心ながら・・・。
-
外池です。
Ao55 さんからの引用 ●”他アプリの作業が終わったら取り除かれる事態は想定されていますでしょうか?”
これは問題ありませんでした。(ご指摘内容を正確に把握していないかも ?)
うーん。問題ナシなら、良いですが・・・。
PAUSEしていないとき、すなわち、掃引描画しているとき、ある程度の時間をかけてグラフが出来上がっていきますよね? その間、何も操作せずにじっと待って、無事次のPAUSEに至れば良いのですが・・・。
グラフが出来上がることを待ちきれずに、ユーザーがたとえば、描画途中のグラフの上にメモ帳を開いて何か作業をして、メモ帳を閉じた。描画途中のグラフがまた現れるハズ? あるいは、ユーザーが何かしなくても、スクリーン・セーバーが起動してしまったので、マウスを動かしてみて、再度表示してみる。正しくグラフが現れる?
こう言う局面では、すべて、Paintのイベントが発生するので、_bmpがFormに描かれてしまって、不都合じゃないのかな? ということです。
他にPaintイベントが発生するケースはいろいろあって、基本的に、プログラマーがPaintイベントの発生を予測することは困難です。ですので、原則、Paintイベントに、画面の描画に必要なすべての手続きを書いておかないといけません。(もちろん、別のサブルーチンにしても良いですが、これを呼び出さないといけません。)
すべての返信
-
Ao55 さん、こんにちは
ダッチです。グラフの描画は何に対して(Form? PictureBox?)、どのタイミング(Paint イベント? OnPaint メソッド?)で行っているのでしょうか。
おそらくボタンをクリックした時に CreateGraphics メソッドを使用して描画しているのではないかと推測して話を進めさせていただきます。このやり方では 掃引画面 に再描画が必要になった時に描画していないため、描画していた内容が消えてしまいます。再描画が必要になったときに描画してやるだけで問題は解決されると思います。
再描画が必要になったときに描画するにはいろいろとやり方があります。
- Paint イベントで描画する
- OnPaint メソッドで描画する
- Image プロパティ(PictureBox の場合)に画像を設定する
参考になる記事がありますので紹介します。
PictureBoxのImageプロパティに関するよくある勘違い
http://dobon.net/vb/dotnet/graphics/pictureboximageanddrawimage.htmlPictureBoxコントロールにグラフィックを描画するには?
http://www.atmarkit.co.jp/fdotnet/dotnettips/458picboxdraw/picboxdraw.html
- Paint イベントで描画する
-
外池と申します。
Ao55さんが遭遇されている問題が、VB6と、VB.NETの一番ギャップの激しいところだと思います。ご苦労が多いと思いますが、頑張ってください。
ダッチさんのご説明にもありますが、要するに、.NETの場合ですと、
-
画面に描いた絵は、まったく「一時的なもの」であること、
-
したがって、自作のアプリの上に、別のアプリのウィンドウを移動してきて隠す、そして、別のアプリのウィンドウを取り除くと、もとの絵が現れることはなく、壊れたままになります。(真っ白だったり、別のアプリの絵が残っていたり)
-
したがって、再度正しく描き直す操作を自作アプリで面倒をみてやらないといけません。描き直すことが必要なタイミングだけは、Windows側から知らせてくれるようになっています。それが、OnPaintというイベントです。
このことをご理解頂いたうえで、じゃぁ、描き直す方法はどうあるべきか? ということになります。
- 画像が、点と線で表現されるもので、点の座標や結ぶ線の色や太さなどの情報がすべて揃っているのであれば、OnPaintの度に、線画で結んでいく要領で描き直すようにできます。表示する画面のサイズが変更された場合に再描画する時でも柔軟に対応ができます。
- 一方で、ビットマップ画像として、自作アプリ内に時々刻々の波形を保管しておくこともできます。で、OnPainのイベントが発生すれば、このビットマップ画像を表示する命令だけを実行すればOKです。VB6時代とほぼ同じ要領のプログラミングが行えます。
もちろん、OnPaintが発生しなくても、自作アプリで次々と新しいデータが入ってきて画面を更新しないといけません。その場合、自作アプリから要求してOnPaintを発生させるわけですが、それが、Refreshメソッドであったり、Invalidateメソッドだったりします。
-
-
中川さん
フォ-ラム初心者で回答済みチェックの場所も よく判らない状態でして すみませんでした。
以下自己レスになりますが真っ白対策 成功しました。方法は
_bmp=new Bitmap(Width,Height) と画像保存先を設定しておいて
1・ PAUSEが発生したら その時の画面を保存する。
Dim g as graphics = Graphics.FromImage(_bmp)
g.CopyFromScreen(New Point(Left、Top) New Point(0,0),_bmp.Size)
2・ 裏-->表になったらPAINTイベントの中で保存画面をコピ-する。
e.Graphics.DrawImage(_bmp,x,y,_bmp.Width,_bmp.Height) x,yはオフセット
これでVB6と大差なく動作できるようになりました。ありがとうございました。
-
外池です。
PAUSEというのは、アプリ自身の動作ですよね・・・。
他アプリが絡んでこないのであれば、お知らせ頂いた方法でOKだと思います。
意地悪な指摘で恐縮なのですが、掃引描画中に他アプリのウィンドウが覆いかぶさって来て、他アプリの作業が終わったら取り除かれる事態は想定されていますでしょうか? 本アプリ自体を最小化して一度消えて、再び表示するようなことも・・・。
今のままだと・・・、ひとつ前のPAUSE画面が再度現れて、そこに現在進行中の掃引状況が重ね書きされるようなことになるのではないかと危惧します。
私のお奨めとしましては、時々刻々の掃引を、_bmpに描き、そのたびに、Me.InvalidateをすればOKかと。
老婆心ながら・・・。
-
外池様 ご指摘ありがとうございます。
●”他アプリの作業が終わったら取り除かれる事態は想定されていますでしょうか?”
これは問題ありませんでした。(ご指摘内容を正確に把握していないかも ?)
●今回のPAUSE対策は画面サイズが変化しない前提です。なので画サイズが変更
されると保存した画像が合いません。そこで画サイズが変更されたらPAUSEを中止して
変更された画サイズで新たに描画を行なっています。●Me.Invalidateはまだ使い方も理解できておりません。HINTをありがとうございました。
今回の問題でVB2005の良い点を見つける事ができました。
_bmp.Save("File-name.png") を行なうだけで画像ファイルとして保存できるんですね。
画面のキャプチャ-+保存が簡単に実現できて驚いています。(VB6では困難でした。)
-
外池です。
Ao55 さんからの引用 ●”他アプリの作業が終わったら取り除かれる事態は想定されていますでしょうか?”
これは問題ありませんでした。(ご指摘内容を正確に把握していないかも ?)
うーん。問題ナシなら、良いですが・・・。
PAUSEしていないとき、すなわち、掃引描画しているとき、ある程度の時間をかけてグラフが出来上がっていきますよね? その間、何も操作せずにじっと待って、無事次のPAUSEに至れば良いのですが・・・。
グラフが出来上がることを待ちきれずに、ユーザーがたとえば、描画途中のグラフの上にメモ帳を開いて何か作業をして、メモ帳を閉じた。描画途中のグラフがまた現れるハズ? あるいは、ユーザーが何かしなくても、スクリーン・セーバーが起動してしまったので、マウスを動かしてみて、再度表示してみる。正しくグラフが現れる?
こう言う局面では、すべて、Paintのイベントが発生するので、_bmpがFormに描かれてしまって、不都合じゃないのかな? ということです。
他にPaintイベントが発生するケースはいろいろあって、基本的に、プログラマーがPaintイベントの発生を予測することは困難です。ですので、原則、Paintイベントに、画面の描画に必要なすべての手続きを書いておかないといけません。(もちろん、別のサブルーチンにしても良いですが、これを呼び出さないといけません。)