環境 : Win2000 VC++6.0 SP5 MFC
初めましてchiakiと申します。過去ログなど参考にさせて頂いてます。
CDC::BitBltを使用したDialogのクライアント領域のCopyについて、
質問させて下さい。
Dialogのクライアント領域に色々描画した後BMPファイルへ保存する
プログラムを作成しています。
概略の流れは、
1.ベースとなるDialog(BaseDlg)を起動させる。
2.描画用のDialog(DrawDlg)をCreateする。
3.BaseDlgからDrawDlgへ描画後、Bitblt,GetDIBitsを使用してファイル
へ保存します。(プログラムの記述はほぼBaseDlgにあります。)
です。
DrawDlgの位置が任意のため、表示画面(0,0)の位置へDrawDlgを移動させ、
メモリDCへBitBltのCopyを行い、DrawDlgを元の位置へ戻しています。
下記のような感じです。
pDrawDlg->ShowWindow(SW_HIDE);
pDrawDlg->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOSIZE);
pDrawDlg->ShowWindow(SW_SHOW);
pDC_MDC_BMP.BitBlt(0, 0, SizeX, SizeY, pDC_DrawDlg, 0, 0, SRCCOPY);
pDrawDlg->ShowWindow(SW_HIDE);
pDrawDlg->SetWindowPos(&wndTop, Xposition, Yposition, 0, 0, SWP_NOSIZE);
pDrawDlg->ShowWindow(SW_SHOW);
この時、DrawDlgの再描画が間に合わず(たぶん)、背景色の画像しか取れません。
BitBlt実行直前に行った描画は取り込めますが、
Draw_DrawDlg(); //DrawDlgへの描画関数を追加した場合
pDC_MDC_BMP.BitBlt(0, 0, SizeX, SizeY, pDC_DrawDlg, 0, 0, SRCCOPY);
DrawDlgにあるコントロールリソース(ScrollBarなど)は取り込めません。
BitBlt実行前にDrawDlgのOnPaintを呼び出しMessageBox等で処理を止めると
ScrollBarなども取り込めるのですが・・・。
Draw_DrawDlg(); //DrawDlgへの描画関数を追加した場合
pDrawDlg->VerOnPaint(); //DrawDlgのOnPaint()を呼びます。
pDC_MDC_BMP.BitBlt(0, 0, SizeX, SizeY, pDC_DrawDlg, 0, 0, SRCCOPY);
--------------------
DrawDlg::VerOnPaint()
{
OnPaint();
MessageBox(",",MB_OK);
}
このような場合の、うまく取り込む方法などありましたら教えて下さい。
よろしくお願いします。
DrawDlgと称しているウインドウの位置づけをどう考えるかでしょうね。
画像の取り込みがDrawDlg上に表示された状態でないといけないのか
どうかで処理自体が変わってくると思います。
DrawDlgと言っているが、実際には描画結果のプレビューのためにあるだけであれば、
BaseDlg側でメモリDCに対して描画を行い、DrawDlg側には描画結果の転送だけで
済むのではないでしょうか?
ファイルに落とすときはメモリDCからファイルに落とせば済む話ですし。
あと、キャプチャするためにウインドウをわざわざ動かすと言うのも変な気がします。
DrawDlgのクライアントDCが得られれば、問題ないと思うのですがちがうんでしょうか。
私なら描画はDrawDlg側に置くと思いますね。
描画に必要な情報をDrawDlg側に引き渡すようにしてDrawDlgのOnPaint内で描画させる
と思います。DrawDlgの描画要求はDrawDlgに行くはずですからDrawDlg内に描画する
部分がないときちんと同期が取れないと思うからです。
キャプチャそのものもDrawDlgにやらせていいと思います。
プログラムを書くだけの立場で考えてしまうと確かにBaseDlg側に処理を置いた方が
楽なのかもしれませんが、本来、その機能を何処に実装するかはそういう観点から
考えるべきではないと思います。
DrawDlg側でやった方が良い場合は、そちらに処理を実装し、それをBaseDlgから
コントロールするようにした方が構成的にはすっきりすると思いますよ。
追加で一言。
OnPaintを単純に呼び出しただけでは、描画はうまくいきません。
実際に描画されるのはクライアント領域無効化されている部分だけです。
再描画させたいのであれば、InvalidateとかUpdateWindowとかを使いましょう。
この辺の描画の仕組みを理解しておかないとWindowsでのプログラミングは
出来ませんので、HELPや参考書席を読んで確認されることをお勧めします。
誤)
実際に描画されるのはクライアント領域無効化されている部分だけです。
正)
実際に描画されるのはクライアント領域の無効化されている部分だけです。
がーん、さらに誤字。
誤)
出来ませんので、HELPや参考書席を読んで確認されることをお勧めします。
正)
出来ませんので、HELPや参考書籍を読んで確認されることをお勧めします。
PATIOさん、ご助言ありがとうございました。
まず最初に、今回問題としていたScrollBarやButtonのリソースのキャプチャ
に関しましては、OnPaint()の代わりにUpdateWindow()を使用することで解決
しました。勉強不足は承知していましたが、InvalidateやUpdateWindowは
入門書の最初頃に出ていた基本関数だったのに。
> この辺の描画の仕組みを理解しておかないとWindowsでのプログラミングは
> 出来ませんので、HELPや参考書籍を読んで確認されることをお勧めします。
ありがとうございました。勉強します。
> DrawDlgと称しているウインドウの位置づけをどう考えるかでしょうね。
表示専用のDialogとして使用しています。主にグラフや波形や表の表示をしています。
最近このような方法を使用するようになったのは、PCの画面サイズの制約からです。
もともとは1つの大き目のDialogでしたが、表示する項目が増えるにつれ、増えた
分を別画面(Dialog)に小分けにして表示するようになりました。ギリギリSVGAサイズ
でも使用できる大きさです。
> あと、キャプチャするためにウインドウをわざわざ動かすと言うのも変な気がします。
> DrawDlgのクライアントDCが得られれば、問題ないと思うのですがちがうんでしょうか。
またしても勉強不足でした。おっしゃる通り、グラフや波形などの自分が描画している
部分はどうにでも成るのですが、Dialogに張り付けてあるScrollBar等の部分が隠れて
いると、どうしてもキャプチャすることができず、その方法がわりませんでした。
DrawDlgのクライアントDCはわかっています。
次はその方法をもう一度調べてみます。
今回は解決ということで、ありがとうございました。
> Dialogに張り付けてあるScrollBar等の部分が隠れていると、
> どうしてもキャプチャすることができず
もう見ていないかもしれませんが。
これについては言われている通りで画面外にある部分は描画されていないかもしれません。
画面外や他の画面に隠されてしまった部分は、描画負荷を減らすために描画対象から外さ
れているでしょうから。
コントロールまでキャプチャしなくてはならない用途というとメニュある作成時のキャプ
チャぐらいしか思いつかないんですが、画面構成とかその他諸々について見直した方が
良いような気がします。
キャプチャしたい画面をメインにすえて移動不可にしてしまった方がよさそうですね。
最大化と最小化だけにするとか。
パラメータの設定とかを子画面にして子画面から設定内容を親画面に通知。
親画面は通知内容で再描画。
キャプチャは子画面が無いときだけOKにしておけば、とりあえず問題は回避できると
思います。
意味不明の文章が。(^^;
誤)
コントロールまでキャプチャしなくてはならない用途というとメニュある作成時のキャプ
チャぐらいしか思いつかないんですが、
正)
コントロールまでキャプチャしなくてはならない用途というとマニュアル作成時のキャプ
チャぐらいしか思いつかないんですが、
後フォローありがとうございます。
了解しました。
何となくできそうな気がしましたもので。
市販ソフトのキャプチャを幾つか見ましたが、画面外は取れて無いようなので
やはり難しいのかな。
PATIOさん、どうもありがとうございました。