dポイントプレゼントキャンペーン実施中!

お世話になります、fujicafeです。
現在、MFCにてダイアログベースのアプリケーションを作成中なのですが、ダイアログにビットマップを貼り付けてOnPaint()で表示するようにプログラムを作成したのですが、何度かダイアログの表示を繰り返すとOnPaintでのビットマップの読み込みが途中まででフリーズしてしまう現象が起きてしまいました。
プログラムは以下のように作成しています
void C****Dlg::OnPaint()
{
 CDC* pDC = this->GetDC();
CDC myDC;
CBitmap newbitmap;
CBitmap* oldbitmap;
CRect rc;
GetClientRect(rc);
newbitmap.LoadBitmap(IDB_BITMAP);
myDC.CreateCompatibleDC( pDC );
oldbitmap=myDC.SelectObject( &newbitmap );
pDC->BitBlt( 0, 0, rc.Width(), rc.Height(), &myDC, 0, 0, SRCCOPY );
myDC.SelectObject(oldbitmap);
}
としています。
初めにこのダイアログを表示時は、ちゃんとビットマップが表示されるのですが、他のダイアログでこのダイアログを表示させた時にビットマップが上半分まで表示されて、動作がフリーズしてしまう現状です。

なにかよい打開策がありましたら、教えていただけたらと思っています。宜しくお願いいたします。

A 回答 (5件)

 こんにちは。

補足頂きました。
 よく考えたら、CBitmapのデストラクタでビットマップが消去されているので、リークではなかったかもしれません。
 http://msdn.microsoft.com/ja-jp/library/wc99t364 …

・なにかまだ考えられることがありましたら宜しくお願い致します。
 取りあえず、当方もフリーズの経験があるのですが、確りとCPaintDCの方を使用していますでしょうか。
 OnPaint()(WM_PAINTメッセージ相当)の中では、GetDC()/ReleaseDC()を使用して描いてはならず、BeginPaint()/EndPaint()相当(CPaintDC)に描かせます。
 http://msdn.microsoft.com/ja-jp/library/a48eab8d …
 http://orangeknowledge.jpn.org/report060325.html

 後、提示したコードが良くなかったかもしれません。以下の様にして見て下さい。

void C****Dlg::OnPaint()
{
CPaintDC paintDC(this);//此れじゃないと問題を起こす事がある
CDC myDC;

CBitmap* oldbitmap;
CRect rc;
GetClientRect(rc);

myDC.CreateCompatibleDC(&paintDC);

oldbitmap=myDC.SelectObject( &m_newbitmap );
paintDC.BitBlt( 0, 0, rc.Width(), rc.Height(), &myDC, 0, 0, SRCCOPY );
myDC.SelectObject(oldbitmap);

//不安なら以下をコメントアウト
//myDC.DeleteDC();
}
    • good
    • 0
この回答へのお礼

詳細な情報ありがとうございます。
早速、ご提示頂いたコードで動作させてみました。
結果としては
前回と同様にフリーズしてしまいました。
コードを提示して頂いて、ただ出来ない出来ないと文句を言っているようで本当に大変申し訳ございません。
私なりにもしらべて見たのですが、4つの各ダイアログを呼び出すメインダイアログ1,2にはピクチャーコントロールがあり、それぞれがビットマップを表示するようにしています。このピクチャーコントロールへのビットマップの貼り付け方法なのですが、ピクチャーコントロールのプロパティでイメージにビットマップのIDを選択させてビットマップを表示させるようにしているのですが、この方法ですと何か問題はありますでしょうか?

背景のビットマップと同様に、各ピクチャーコントロールに対するビットマップもOnInitialDialog()内で貼り付けて、OnPaintでBitBltで表示するようにしたらよいのでしょうか。
質問するくらいなら実際にやればいいのでしょうが、なぜかうまくその方法ですとピクチャーコントロールに画像が描画されないため悩んでいるところです。
たびたびの質問で申し訳ございません。

お礼日時:2009/05/20 13:39

>何度かダイアログの表示を繰り返すとOnPaintでのビットマップの読み込みが途中まででフリーズしてしまう現象が起きてしまいました。



デバイスコンテキストを「使いっぱなし」にしてはいけません。使った物はちゃんと片付けましょう。

GetDCした場合、そのデバイスコンテキストを使い終わったらReleaseDCしなければなりません。

ReleaseDCをせずにGetDCを何度も繰り返すと、デバイスコンテキストのロックリソースが尽き、デバイスコンテキストへのアクセスが出来なくなったり(つまり、画面の描画が出来なくなったり)、スレッドが応答しなくなったりします。

また、CreateCompatibleDCで作成したデバイスコンテキストも、使い終わったらDeleteObjectで削除しなければなりません。

DeleteObjectをせずにCreateCompatibleDCを何度も繰り返すと、デバイスコンテキストのリソースが尽き、デバイスコンテキストへのアクセスが出来なくなったり(つまり、画面の描画が出来なくなったり)、スレッドが応答しなくなったりします。

以下の2点にご注意下さい。

・GetDCでデバイスコンテキストを占有した場合は、必ずReleaseDCで不要になったデバイスコンテキストのロックを解除して開放すること。

・CreateCompatibleDCでデバイスコンテキストを作成した場合は、必ずDeleteObjectで不要になったデバイスコンテキストを削除すること。

因みに、デバイスコンテキストは「各スレッドで同時に使えるのは16個くらい」なので、ダイアログの表示を5~8回も行えば、デバイスコンテキストのリソースが尽き、プロセスがフリーズするでしょう。

なお、あくまでも「同時に使えるのは」です。

なので「占有→使用→開放を16回以上」はOKです。これは「同時に使っているのは1個だけ」なので、何の問題もありません。

ですが「占有→使用→放置を16回以上」はNGです。これは「同時に使っているのは16個以上」なので、リソース不足でダウンします(質問者さんのプログラムが、この状態になっている)
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
早速、CreateCompatibleDCを仕様したデバイスコンテキストをDeleteObjectしてみたのですが、やはりフリーズします。
そこで、CpaintDCを使用してBitBltしている箇所をあえて、
CDC* pDC = this->GetDC();
でデバイスコンテキストを取得し、最後にReleaseDCで解除するように変更したのですが、やはりフリーズしてしまいました。

呼び出す側のピクチャーコントロールへのビットマップの貼り付けをはずすか、呼ばれるダイアログの背景のビットマップの貼り付けをはずすとフリーズせずに動作するようなのですが、これは使用しているマシンの性能の問題なのでしょうか?
開発で使用しているマシンがPCではなく、組み込みのマシンのためそういう問題もあるのかなと思っています。

お礼日時:2009/05/20 15:39

CBitmap が、どう振舞うのか?


メモリデバイスコンテキストはどう使うのか?
このあたりの基本を勉強したほうがいいです。

newbitmap もメンバにしないといけないはずです。
    • good
    • 0
この回答へのお礼

ご指示ありがとうございます。
確かに、本やネットをみて、このコードでならビットマップ
が貼り付けれるとしか考えていなかったです。
しっかりとメモリデバイスコンテキストの振る舞いやCBitmap
について勉強し直さなければならないみたいです。

CBitmapをメンバ変数にしてみましたが、結果は変わらずでした。
もしかしたら
ダイアログ内のピクチャーボックスにビットマップを貼り付けている
のですが、その貼り付け方法がプロパティのイメージでビットマップの
IDを選択している
ということも影響の要因なのかなと思っています。
これも関係ありますでしょうか?

お礼日時:2009/05/20 12:48

myDCはメンバ変数にして、


OnPaintでは、BitBltだけするようにしたほうがいいですよ。
    • good
    • 0
この回答へのお礼

早速の返信ありがとうございます。
myDCをメンバ変数とすると、ダイアログ上のコントロールをクリック
するとエラーがでてストップしてしまうみたいです。
myDCを元のOnPaint()上に戻すと、コントロールは動作しますがやはりビットマップ呼び出し時にフリーズしてしまいます。

お礼日時:2009/05/20 09:19

 こんばんは。


 OnPaint()が呼ばれる度に、ビットマップをリソースからロードしているので、リークを起こしているのではないでしょうか。
 newbitmapをメンバ変数にして、OnInitDialog()で作成して置くのが無難です。
 後、OnPaint()でダイアログに描写する際は、CDCではなくて、PaintDCの方ではないでしょうか。
 以下では駄目でしょうか。

class C****Dlg
{
private:
CBitmap m_newbitmap;//ヘッダに移動
};

BOOL C****Dlg::OnInitDialog()
{
// TODO: 特別な初期化を行う時はこの場所に追加してください。

//此処で作成しておく
m_newbitmap.LoadBitmap(IDB_BITMAP);

return TRUE; // TRUE を返すとコントロールに設定したフォーカスは失われません。
}

void C****Dlg::OnPaint()
{
//再描画で使用するDC
CPaintDC paintDC(this);
CDC myDC;

CBitmap* oldbitmap;
CRect rc;
GetClientRect(rc);

//互換メモリデバイスコンテキストの作成
CDC* pDC = this->GetDC();
myDC.CreateCompatibleDC(pDC);
ReleaseDC(pDC);

//選択して書く
oldbitmap=myDC.SelectObject( &m_newbitmap );
paintDC.BitBlt( 0, 0, rc.Width(), rc.Height(), &myDC, 0, 0, SRCCOPY );
myDC.SelectObject(oldbitmap);
}

この回答への補足

もう一つ付け加えなのですが、メインダイアログ1で4つのダイアログ
を各コントロールから呼び出す際には今回のような症状が出ていません。
メインダイアログ1からメインダイアログ2を呼び出して、さらにそこから4つのダイアログを呼び出していった時の4番目のダイアログの呼び出し時に必ずこの現象が生じるようです。

補足日時:2009/05/20 09:28
    • good
    • 0
この回答へのお礼

丁寧な説明ありがとうございます。
早速、教えて頂いた通りにビットマップの呼び出しをOnInitDialog()
に移動させ、OnPaint()内ではBitBltのみを処理するようにして観ました。
結果としては、以前と同様にビットマップの呼び出しで動作がフリーズしてしまいます。でも、確かにメモリリークを起こしているような気がします。
現在のプログラムの詳細な状況を説明させていただきますと、
メインのダイアログが2つありまして、それをメインダイアログ1,メインダイアログ2とします。
メインダイアログ1からメインダイアログ2を呼び出すにはF1キーで呼び出します。メインダイアログ1,メインダイアログ2にはそれぞれ同じボタンが4つありまして、4つのボタンで4つのダイアログを表示させます。ダイアログは全て背景をビットマップとしています。
現在の症状としては、フリーズするときにはダイアログ上の背景ビットマップが約上半分表示され、ダイアログ上のコントロールは全て空白となり、呼び出したメインダイアログの背景が透けて見えるといった状況です。
開発環境がWindows CE6.0でVisualStudio2005なのが不安ではあるのですが、なにかまだ考えられることがありましたら宜しくお願い致します。

お礼日時:2009/05/20 09:27

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!