「裏画面」を使用するには?

解決


mossan  2003-12-12 13:10:51  No: 52867  IP: [192.*.*.*]

ボタンを押すと、ピクチャボックスにMoveToとLineToで描画した直線を描き、それが移動していくようなプログラムを作りたいと思っています。
ただ、普通に描いただけでは、描画の様子が目に見えてしまうので、
すべてが描き終わってから表示させるように、ある領域を用意しておいて、
描画をそちらにしたあと、その内容をピクチャボックスに転送する方法を取りたいと思っているのですが、どうもうまくいきません。
以下はボタンのコード内容です。

void CTestView::OnBnClickedButton1()
{
CDC* pDC=m_pict.GetDC();//m_pictはピクチャボックスのコントロール変数
CDC workDC;            //描画用領域
m_pict.GetClientRect(myRECT);
workDC.CreateCompatibleDC(pDC);//領域の形式をコピー
workDC.FillSolidRect(myRECT,RGB(255,255,255));//白く塗りつぶしておく
for (int i=0;i<=10;i++){
  workDC.MoveTo(i,100);
  workDC.LineTo(i+10,100);
  pDC->BitBlt(0,0,300,300,&workDC,0,0,SRCCOPY);
  }
m_pict.ReleaseDC(pDC);
}

これで直線が移動していくようなプログラムが動くかと思ったのですが、
何も起こりません。そもそもどこで描画が行われるのかがわかっていないので、そのあたりも含め、ご教授ください。
よろしくお願いいたします。

編集 削除
YuO  2003-12-12 13:33:54  No: 52868  IP: [192.*.*.*]

> for (int i=0;i<=10;i++){
>   workDC.MoveTo(i,100);
>   workDC.LineTo(i+10,100);
>   pDC->BitBlt(0,0,300,300,&workDC,0,0,SRCCOPY);
>   }
> m_pict.ReleaseDC(pDC);
> }
> これで直線が移動していくようなプログラムが動くかと思ったのですが、
> 何も起こりません。そもそもどこで描画が行われるのかがわかっていないので、そのあたりも含め、ご教授ください。

これでは一瞬にして描いてしまいます。
裏画面を利用する意味はないと思います。
#毎回BitBltしちゃあ……。

タイマーを利用して,時間をかけて描画する必要があると思います。

編集 削除
岡田 之仁  2003-12-12 13:45:23  No: 52869  IP: [192.*.*.*]

採用された方法と、行いたい内容がチグハグです。
通常は高速に描画を行いたいので、『別の場所』と言う
メモリデバイスコンテキストに書いて、BitBlt等で、表
に一気に書く・・・ダブルバッファリングともいいます
が・・・

ですが、描画の進行を見えるようにしたいなら、わざわざ
ダブルバッファリング方法を採用しなくても、ダイレクト
に表の描画領域に書くとか、要素毎にウェイト入れるとか・・・

ですが、直線は一気に書かれてしまうので、それを線を引
いているかのように見せるなら、点の集合のようにして、
『見える』ように書かないといけないことになります。
当然、円や曲線もしかりです。

ご検討下さい。

以上。

編集 削除
mossan  2003-12-12 14:31:01  No: 52870  IP: [192.*.*.*]

YuOさん、岡田 之仁さん、ご回答ありがとうございました。
申し訳ありません。説明のためプログラムを簡略化してしまったのがいけませんでした。また、まったく説明が足りてませんでした。

私が最終的に行いたいのは、
「多くの直線(5000本ほど?)を画面に表示する」
「その直線がそれぞれ動いているような動作をする」
ということです。

私は一度直接画面に書く方法を取ってみたのですが、問題点として、
「5000本の直線を描くとき、最初に書いた直線と最後に書いた直線にタイムラグがあり、一枚の絵として表示できない」
「また、『直線を描く→画面をクリア→次の直線の動きを描く→画面をクリア→・・・』という方式を取ると画面が点滅しているように見えて、非常に見づらい」

この二つの問題を解消する方式として、裏画面を使ったダブルバッファリングが良いのではないかということを考えました。
つまり、
「多くの直線を裏画面に書いておく→表に表示する→次の直線を裏画面に書く→表に上書きする→・・・」とすればよいのではないか?と考えました。

しかし、上に書いた簡略化したプログラムでも、何も表示されず、どうしていいのかわかりません。

私が知りたいのは、
「上のプログラムはなぜ何も表示されないのか?」
「ダブルバッファリングを用いた描画の上手な方法は?」
ということです。

引き続き、よろしくお願いいたします。

編集 削除
AE  2003-12-12 14:55:52  No: 52871  IP: [192.*.*.*]

>「上のプログラムはなぜ何も表示されないのか?」

>workDC.CreateCompatibleDC(pDC);//領域の形式をコピー
で作られたDCの初期状態で選択されているのはは1x1のビットマップです。
裏画面用のビットマップを用意してSelectObjectしてください。

編集 削除
mossan  2003-12-17 03:14:51  No: 52872  IP: [192.*.*.*]

AEさんお返事遅れて申し訳ありませんでした。
AEさんの言うとおりに、リソースに空のビットマップを追加し、
LoadBitmap
SelectObjectとを組み合わせてできました。
本当にありがとうございました。

編集 削除
なーめ  2003-12-17 04:01:21  No: 52873  IP: [192.*.*.*]

解決済みではありますが。
>> AEさんの言うとおりに、リソースに空のビットマップを追加し、
>> LoadBitmap
>> SelectObjectとを組み合わせてできました。
AE さんのところまではいいのですが、その先、
空のビットマップなど、リソース(exe のサイズ)の無駄ですよ。
それに画像サイズを変えるとき、リソースの画像をリサイズするのですか?
保守性が悪いですね。
次のコードなら定数(640,480)を変えるだけです、
変数にすれば、ファイルやレジストリから読み込んだ値で作成できます。
なお、OnPaint で毎回 CreateXXX/DeleteXXX するのも処理の無駄なので、
表示するウィンドウのクラスのメンバ変数にしておくき、
ウィンドウクラスの初期化と、終了処理で行えばいいでしょう。
#使い捨てコードなら別に気にしなくてもかまいませんが....。

  CDC * pDC = GetDC();
  CDC memDC;
  CBitmap bmp,*pbmp;
  memDC.CreateCompatibleDC( pDC );
  bmp.CreateCompatibleBitmap( pDC, 640, 480 ); // たとえば 640x480
  pbmp = memDC.SelectObject( &bmp );
  //// memDC 作業
  memDC.SelectObject( pbmp );
  memDC.DeleteDC();
  bmp.DeleteObject();
  ReleaseDC( pDC );

編集 削除