none
VB2005でグラフ画像を裏-->表にすると真白になってしまいます。 RRS feed

  • 質問

  • VB6からVB2005に最近乗り換えたばかりです。VB6で出来ていた事がVB2005で出来ずに悩んでいます。内容はLINE関数でグラフを掃引描画してオシロスコ-プのように波形を描かせています。これにPAUSE機能を追加して掃引を停止した状態で他のアプリ作業を行ないます。当然アプリ作業画面がアクティブ(表)となり掃引画面は(裏)となります。アプリ作業が終了して再度掃引画面が(表)となった時VB6では自動的に以前の掃引画面が復元して問題ありません。しかしVB2005では(裏)となっていた部分が真っ白になったままで復元が出来ません。これをVB6と同じように自動で復元できるように設定する方法があるのでしょうか? よろしくお願いします。

     

     

    2008年2月23日 5:48

回答

  • Ao55 さん、こんにちは
    ダッチです。

     

    グラフの描画は何に対して(Form? PictureBox?)、どのタイミング(Paint イベント? OnPaint メソッド?)で行っているのでしょうか。

     

    おそらくボタンをクリックした時に CreateGraphics メソッドを使用して描画しているのではないかと推測して話を進めさせていただきます。このやり方では 掃引画面 に再描画が必要になった時に描画していないため、描画していた内容が消えてしまいます。再描画が必要になったときに描画してやるだけで問題は解決されると思います。


    再描画が必要になったときに描画するにはいろいろとやり方があります。

    • Paint イベントで描画する
    • OnPaint メソッドで描画する
    • Image プロパティ(PictureBox の場合)に画像を設定する

     

    参考になる記事がありますので紹介します。

     

    PictureBoxのImageプロパティに関するよくある勘違い
    http://dobon.net/vb/dotnet/graphics/pictureboximageanddrawimage.html

    PictureBoxコントロールにグラフィックを描画するには?

    http://www.atmarkit.co.jp/fdotnet/dotnettips/458picboxdraw/picboxdraw.html

    2008年2月23日 6:59
  • 外池と申します。

     

    Ao55さんが遭遇されている問題が、VB6と、VB.NETの一番ギャップの激しいところだと思います。ご苦労が多いと思いますが、頑張ってください。

     

    ダッチさんのご説明にもありますが、要するに、.NETの場合ですと、

    • 画面に描いた絵は、まったく「一時的なもの」であること、
    • したがって、自作のアプリの上に、別のアプリのウィンドウを移動してきて隠す、そして、別のアプリのウィンドウを取り除くと、もとの絵が現れることはなく、壊れたままになります。(真っ白だったり、別のアプリの絵が残っていたり)
    • したがって、再度正しく描き直す操作を自作アプリで面倒をみてやらないといけません。描き直すことが必要なタイミングだけは、Windows側から知らせてくれるようになっています。それが、OnPaintというイベントです。

    このことをご理解頂いたうえで、じゃぁ、描き直す方法はどうあるべきか? ということになります。

    • 画像が、点と線で表現されるもので、点の座標や結ぶ線の色や太さなどの情報がすべて揃っているのであれば、OnPaintの度に、線画で結んでいく要領で描き直すようにできます。表示する画面のサイズが変更された場合に再描画する時でも柔軟に対応ができます。
    • 一方で、ビットマップ画像として、自作アプリ内に時々刻々の波形を保管しておくこともできます。で、OnPainのイベントが発生すれば、このビットマップ画像を表示する命令だけを実行すればOKです。VB6時代とほぼ同じ要領のプログラミングが行えます。

    もちろん、OnPaintが発生しなくても、自作アプリで次々と新しいデータが入ってきて画面を更新しないといけません。その場合、自作アプリから要求してOnPaintを発生させるわけですが、それが、Refreshメソッドであったり、Invalidateメソッドだったりします。

    2008年2月23日 8:52
  • こんにちは。中川俊輔 です。

     

    ダッチさん、外池さん、大変参考になる回答ありがとうございます。

     

    Ao55さん、フォーラムのご利用ありがとうございます。

    問題が解決されたようなので、勝手ながらダッチさん、外池さんの回答へ回答済みチェックをつけさせていただきました。

     

    回答済みチェックが付くことにより、有用な情報を探している方が情報を見つけやすくなります。
    問題解決につながる回答があった場合は、なるべく回答済みボタンを押してチェックを付けてください。

    Ao55さんはチェックを解除することもできますので、ご確認ください。

     

    それでは!

     

    2008年2月26日 8:46
  • 外池です。

     

    PAUSEというのは、アプリ自身の動作ですよね・・・。

    他アプリが絡んでこないのであれば、お知らせ頂いた方法でOKだと思います。

     

    意地悪な指摘で恐縮なのですが、掃引描画中に他アプリのウィンドウが覆いかぶさって来て、他アプリの作業が終わったら取り除かれる事態は想定されていますでしょうか? 本アプリ自体を最小化して一度消えて、再び表示するようなことも・・・。

     

    今のままだと・・・、ひとつ前のPAUSE画面が再度現れて、そこに現在進行中の掃引状況が重ね書きされるようなことになるのではないかと危惧します。

     

    私のお奨めとしましては、時々刻々の掃引を、_bmpに描き、そのたびに、Me.InvalidateをすればOKかと。

     

    老婆心ながら・・・。

     

    2008年2月28日 4:36
  • 外池です。

     

     Ao55 さんからの引用

    ●”他アプリの作業が終わったら取り除かれる事態は想定されていますでしょうか?”

      これは問題ありませんでした。(ご指摘内容を正確に把握していないかも ?)

     

    うーん。問題ナシなら、良いですが・・・。

     

    PAUSEしていないとき、すなわち、掃引描画しているとき、ある程度の時間をかけてグラフが出来上がっていきますよね? その間、何も操作せずにじっと待って、無事次のPAUSEに至れば良いのですが・・・。

     

    グラフが出来上がることを待ちきれずに、ユーザーがたとえば、描画途中のグラフの上にメモ帳を開いて何か作業をして、メモ帳を閉じた。描画途中のグラフがまた現れるハズ? あるいは、ユーザーが何かしなくても、スクリーン・セーバーが起動してしまったので、マウスを動かしてみて、再度表示してみる。正しくグラフが現れる?

     

    こう言う局面では、すべて、Paintのイベントが発生するので、_bmpがFormに描かれてしまって、不都合じゃないのかな? ということです。

     

    他にPaintイベントが発生するケースはいろいろあって、基本的に、プログラマーがPaintイベントの発生を予測することは困難です。ですので、原則、Paintイベントに、画面の描画に必要なすべての手続きを書いておかないといけません。(もちろん、別のサブルーチンにしても良いですが、これを呼び出さないといけません。)

     

     

     

     

     

    2008年2月28日 6:21
  • 外池です。

     

    貴アプリの描画全体の流れを理解していないのでなんとも申し上げられませんが、最初のPAUSEより前で_bmpが「空」なのであれば、何も出てこないんでしょうね・・・。

     

    他のアプリの窓でもExplorerのファイルの一覧の窓でもなんでもいいので、スィープ描画中の貴アプリの窓を覆う形で、バタバタやってみて(変な表現ですが)、動作チェックをしてみるのがよろしいかと。

     

    このあたり・・・、結構、ハマること多いです。

     

     

     

     

     

    2008年2月28日 9:04

すべての返信

  • Ao55 さん、こんにちは
    ダッチです。

     

    グラフの描画は何に対して(Form? PictureBox?)、どのタイミング(Paint イベント? OnPaint メソッド?)で行っているのでしょうか。

     

    おそらくボタンをクリックした時に CreateGraphics メソッドを使用して描画しているのではないかと推測して話を進めさせていただきます。このやり方では 掃引画面 に再描画が必要になった時に描画していないため、描画していた内容が消えてしまいます。再描画が必要になったときに描画してやるだけで問題は解決されると思います。


    再描画が必要になったときに描画するにはいろいろとやり方があります。

    • Paint イベントで描画する
    • OnPaint メソッドで描画する
    • Image プロパティ(PictureBox の場合)に画像を設定する

     

    参考になる記事がありますので紹介します。

     

    PictureBoxのImageプロパティに関するよくある勘違い
    http://dobon.net/vb/dotnet/graphics/pictureboximageanddrawimage.html

    PictureBoxコントロールにグラフィックを描画するには?

    http://www.atmarkit.co.jp/fdotnet/dotnettips/458picboxdraw/picboxdraw.html

    2008年2月23日 6:59
  • 外池と申します。

     

    Ao55さんが遭遇されている問題が、VB6と、VB.NETの一番ギャップの激しいところだと思います。ご苦労が多いと思いますが、頑張ってください。

     

    ダッチさんのご説明にもありますが、要するに、.NETの場合ですと、

    • 画面に描いた絵は、まったく「一時的なもの」であること、
    • したがって、自作のアプリの上に、別のアプリのウィンドウを移動してきて隠す、そして、別のアプリのウィンドウを取り除くと、もとの絵が現れることはなく、壊れたままになります。(真っ白だったり、別のアプリの絵が残っていたり)
    • したがって、再度正しく描き直す操作を自作アプリで面倒をみてやらないといけません。描き直すことが必要なタイミングだけは、Windows側から知らせてくれるようになっています。それが、OnPaintというイベントです。

    このことをご理解頂いたうえで、じゃぁ、描き直す方法はどうあるべきか? ということになります。

    • 画像が、点と線で表現されるもので、点の座標や結ぶ線の色や太さなどの情報がすべて揃っているのであれば、OnPaintの度に、線画で結んでいく要領で描き直すようにできます。表示する画面のサイズが変更された場合に再描画する時でも柔軟に対応ができます。
    • 一方で、ビットマップ画像として、自作アプリ内に時々刻々の波形を保管しておくこともできます。で、OnPainのイベントが発生すれば、このビットマップ画像を表示する命令だけを実行すればOKです。VB6時代とほぼ同じ要領のプログラミングが行えます。

    もちろん、OnPaintが発生しなくても、自作アプリで次々と新しいデータが入ってきて画面を更新しないといけません。その場合、自作アプリから要求してOnPaintを発生させるわけですが、それが、Refreshメソッドであったり、Invalidateメソッドだったりします。

    2008年2月23日 8:52
  • 外池さん ダッチさん 早速の回答をありがとうございます。
    VB6のように自動で復元してくれる機能がVB2005にも用意されているのかも? と期待していましたが
    そのような機能は用意されていなくて自分で画像保存-->復元を行なわなければならないとの事ですね。
    わかりました。教えていただいたLINKなど参考にして機能追加を行ないます。
    ありがとうございました。

     

     

    2008年2月24日 10:28
  • こんにちは。中川俊輔 です。

     

    ダッチさん、外池さん、大変参考になる回答ありがとうございます。

     

    Ao55さん、フォーラムのご利用ありがとうございます。

    問題が解決されたようなので、勝手ながらダッチさん、外池さんの回答へ回答済みチェックをつけさせていただきました。

     

    回答済みチェックが付くことにより、有用な情報を探している方が情報を見つけやすくなります。
    問題解決につながる回答があった場合は、なるべく回答済みボタンを押してチェックを付けてください。

    Ao55さんはチェックを解除することもできますので、ご確認ください。

     

    それでは!

     

    2008年2月26日 8:46
  • 中川さん

    フォ-ラム初心者で回答済みチェックの場所も よく判らない状態でして すみませんでした。

     

    以下自己レスになりますが真っ白対策 成功しました。方法は

    _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と大差なく動作できるようになりました。ありがとうございました。

    2008年2月28日 4:13
  • 外池です。

     

    PAUSEというのは、アプリ自身の動作ですよね・・・。

    他アプリが絡んでこないのであれば、お知らせ頂いた方法でOKだと思います。

     

    意地悪な指摘で恐縮なのですが、掃引描画中に他アプリのウィンドウが覆いかぶさって来て、他アプリの作業が終わったら取り除かれる事態は想定されていますでしょうか? 本アプリ自体を最小化して一度消えて、再び表示するようなことも・・・。

     

    今のままだと・・・、ひとつ前のPAUSE画面が再度現れて、そこに現在進行中の掃引状況が重ね書きされるようなことになるのではないかと危惧します。

     

    私のお奨めとしましては、時々刻々の掃引を、_bmpに描き、そのたびに、Me.InvalidateをすればOKかと。

     

    老婆心ながら・・・。

     

    2008年2月28日 4:36
  • 外池様  ご指摘ありがとうございます。

    ●”他アプリの作業が終わったら取り除かれる事態は想定されていますでしょうか?”

      これは問題ありませんでした。(ご指摘内容を正確に把握していないかも ?)
    ●今回のPAUSE対策は画面サイズが変化しない前提です。なので画サイズが変更
     されると保存した画像が合いません。そこで画サイズが変更されたらPAUSEを中止して
     変更された画サイズで新たに描画を行なっています。

    ●Me.Invalidateはまだ使い方も理解できておりません。HINTをありがとうございました。

     

    今回の問題でVB2005の良い点を見つける事ができました。

    _bmp.Save("File-name.png") を行なうだけで画像ファイルとして保存できるんですね。

    画面のキャプチャ-+保存が簡単に実現できて驚いています。(VB6では困難でした。)

     

     

    2008年2月28日 5:58
  • 外池です。

     

     Ao55 さんからの引用

    ●”他アプリの作業が終わったら取り除かれる事態は想定されていますでしょうか?”

      これは問題ありませんでした。(ご指摘内容を正確に把握していないかも ?)

     

    うーん。問題ナシなら、良いですが・・・。

     

    PAUSEしていないとき、すなわち、掃引描画しているとき、ある程度の時間をかけてグラフが出来上がっていきますよね? その間、何も操作せずにじっと待って、無事次のPAUSEに至れば良いのですが・・・。

     

    グラフが出来上がることを待ちきれずに、ユーザーがたとえば、描画途中のグラフの上にメモ帳を開いて何か作業をして、メモ帳を閉じた。描画途中のグラフがまた現れるハズ? あるいは、ユーザーが何かしなくても、スクリーン・セーバーが起動してしまったので、マウスを動かしてみて、再度表示してみる。正しくグラフが現れる?

     

    こう言う局面では、すべて、Paintのイベントが発生するので、_bmpがFormに描かれてしまって、不都合じゃないのかな? ということです。

     

    他にPaintイベントが発生するケースはいろいろあって、基本的に、プログラマーがPaintイベントの発生を予測することは困難です。ですので、原則、Paintイベントに、画面の描画に必要なすべての手続きを書いておかないといけません。(もちろん、別のサブルーチンにしても良いですが、これを呼び出さないといけません。)

     

     

     

     

     

    2008年2月28日 6:21
  • 外池さん
    詳細な説明をありがとうございます。やっと意味が判りました。
    PAUSEがOffの時は掃引描画しています。考え方としては その途中で もしPaintイベントが発生した時はPAUSE=Offの時は何もしないと記述すれば不具合を避けられると思いますが・・・・
    ところが現在のソフトは その条件を付けていないのに保存画面が出てきません。これは何故 ?
    外池さんが指摘されたように保存画面が現れるはずなのに・・・・・・?????

     

     

     

    2008年2月28日 8:57
  • 外池です。

     

    貴アプリの描画全体の流れを理解していないのでなんとも申し上げられませんが、最初のPAUSEより前で_bmpが「空」なのであれば、何も出てこないんでしょうね・・・。

     

    他のアプリの窓でもExplorerのファイルの一覧の窓でもなんでもいいので、スィープ描画中の貴アプリの窓を覆う形で、バタバタやってみて(変な表現ですが)、動作チェックをしてみるのがよろしいかと。

     

    このあたり・・・、結構、ハマること多いです。

     

     

     

     

     

    2008年2月28日 9:04
  • 外池さん

     

    こんなことまで おつきあいしていただき ありがとうございます。


    _bmpが"空"ならば・・・・・で気が付きました。プログラムの初期設定で”空”にしていました。
        _bmp=new Bitmap(Width,Height)
    PAUSEを終了すると この初期設定を通過するので結果OKになっていましたがWINDOWSの挙動にまで配慮せずに作っていました。

    2008年2月28日 12:48
  • いえ・・・、雑談になってしまいますが・・・、

     

    純粋に計算結果(シミュレーション結果)にせよ、測定値にせよ、時々刻々の値の変化をグラフにして表示するというタスクが、私の本来業務で多いので、また、VB6からVB.NETへの移行では、私も相当勉強したりプログラム試作をしたりしましたので、「気になる」という感じです。

     

     

    2008年2月28日 14:29