• ベストアンサー

ダイアログにビットマップを貼り付けた時にフリーズしてしまう

お世話になります、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); } としています。 初めにこのダイアログを表示時は、ちゃんとビットマップが表示されるのですが、他のダイアログでこのダイアログを表示させた時にビットマップが上半分まで表示されて、動作がフリーズしてしまう現状です。 なにかよい打開策がありましたら、教えていただけたらと思っています。宜しくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

 こんにちは。補足頂きました。  よく考えたら、CBitmapのデストラクタでビットマップが消去されているので、リークではなかったかもしれません。  http://msdn.microsoft.com/ja-jp/library/wc99t364(VS.80).aspx ・なにかまだ考えられることがありましたら宜しくお願い致します。  取りあえず、当方もフリーズの経験があるのですが、確りとCPaintDCの方を使用していますでしょうか。  OnPaint()(WM_PAINTメッセージ相当)の中では、GetDC()/ReleaseDC()を使用して描いてはならず、BeginPaint()/EndPaint()相当(CPaintDC)に描かせます。  http://msdn.microsoft.com/ja-jp/library/a48eab8d(VS.80).aspx  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(); }

fujtomo
質問者

お礼

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

その他の回答 (4)

  • chie65535
  • ベストアンサー率43% (8525/19381)
回答No.5

>何度かダイアログの表示を繰り返すとOnPaintでのビットマップの読み込みが途中まででフリーズしてしまう現象が起きてしまいました。 デバイスコンテキストを「使いっぱなし」にしてはいけません。使った物はちゃんと片付けましょう。 GetDCした場合、そのデバイスコンテキストを使い終わったらReleaseDCしなければなりません。 ReleaseDCをせずにGetDCを何度も繰り返すと、デバイスコンテキストのロックリソースが尽き、デバイスコンテキストへのアクセスが出来なくなったり(つまり、画面の描画が出来なくなったり)、スレッドが応答しなくなったりします。 また、CreateCompatibleDCで作成したデバイスコンテキストも、使い終わったらDeleteObjectで削除しなければなりません。 DeleteObjectをせずにCreateCompatibleDCを何度も繰り返すと、デバイスコンテキストのリソースが尽き、デバイスコンテキストへのアクセスが出来なくなったり(つまり、画面の描画が出来なくなったり)、スレッドが応答しなくなったりします。 以下の2点にご注意下さい。 ・GetDCでデバイスコンテキストを占有した場合は、必ずReleaseDCで不要になったデバイスコンテキストのロックを解除して開放すること。 ・CreateCompatibleDCでデバイスコンテキストを作成した場合は、必ずDeleteObjectで不要になったデバイスコンテキストを削除すること。 因みに、デバイスコンテキストは「各スレッドで同時に使えるのは16個くらい」なので、ダイアログの表示を5~8回も行えば、デバイスコンテキストのリソースが尽き、プロセスがフリーズするでしょう。 なお、あくまでも「同時に使えるのは」です。 なので「占有→使用→開放を16回以上」はOKです。これは「同時に使っているのは1個だけ」なので、何の問題もありません。 ですが「占有→使用→放置を16回以上」はNGです。これは「同時に使っているのは16個以上」なので、リソース不足でダウンします(質問者さんのプログラムが、この状態になっている)

fujtomo
質問者

お礼

ご回答ありがとうございます。 早速、CreateCompatibleDCを仕様したデバイスコンテキストをDeleteObjectしてみたのですが、やはりフリーズします。 そこで、CpaintDCを使用してBitBltしている箇所をあえて、 CDC* pDC = this->GetDC(); でデバイスコンテキストを取得し、最後にReleaseDCで解除するように変更したのですが、やはりフリーズしてしまいました。 呼び出す側のピクチャーコントロールへのビットマップの貼り付けをはずすか、呼ばれるダイアログの背景のビットマップの貼り付けをはずすとフリーズせずに動作するようなのですが、これは使用しているマシンの性能の問題なのでしょうか? 開発で使用しているマシンがPCではなく、組み込みのマシンのためそういう問題もあるのかなと思っています。

  • takoashi
  • ベストアンサー率39% (21/53)
回答No.3

CBitmap が、どう振舞うのか? メモリデバイスコンテキストはどう使うのか? このあたりの基本を勉強したほうがいいです。 newbitmap もメンバにしないといけないはずです。

fujtomo
質問者

お礼

ご指示ありがとうございます。 確かに、本やネットをみて、このコードでならビットマップ が貼り付けれるとしか考えていなかったです。 しっかりとメモリデバイスコンテキストの振る舞いやCBitmap について勉強し直さなければならないみたいです。 CBitmapをメンバ変数にしてみましたが、結果は変わらずでした。 もしかしたら ダイアログ内のピクチャーボックスにビットマップを貼り付けている のですが、その貼り付け方法がプロパティのイメージでビットマップの IDを選択している ということも影響の要因なのかなと思っています。 これも関係ありますでしょうか?

  • takoashi
  • ベストアンサー率39% (21/53)
回答No.2

myDCはメンバ変数にして、 OnPaintでは、BitBltだけするようにしたほうがいいですよ。

fujtomo
質問者

お礼

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

回答No.1

 こんばんは。  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); }

fujtomo
質問者

お礼

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

fujtomo
質問者

補足

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

関連するQ&A

  • VisualC++6.0にてボタンにビットマップを表示させる方法

    VisualC++6.0のダイアログベースのアプリにおいて、 フォーム上に配置したボタン上にビットマップを表示 させたいと思ってます。OnPaint()の中で、以下のコード を書いたのですが、うまくいきません。  CWnd* myWnd = GetDlgItem(IDC_BUTTON1);  CDC* pDC = myWnd->GetDC();  CDC myDC;  CBitmap myBMP;  myBMP.LoadBitmap(IDB_BITMAP);  myDC.CreateCompatibleDC(pDC);  CBitmap* oldBMP = myDC.SelectObject(&myBMP);  pDC->BitBlt(0,0,100,100,&myDC,0,0,SRCCOPY);  myDC.SelectObject(oldBMP); ビットマップはちゃんと書かれてはいますが、その上にボタンが 描かれてしまうので、ビットマップが隠されてしまいます。 解決方法を教えてくださいますでしょうか。 よろしくお願いします。 % 絵をクリックするとアクションを起こすようにしたいので、 % ピクチャーボックスでも試してみました。これだとビット % マップはちゃんと表示されますが、BN_CLICKEDを書いて % ピクチャーボックスをクリックしてもOnPict()に処理が % 移りません。

  • 画像の印刷について

    環境はWIN98 VC++6.0 MFCです。 初めて印刷に挑戦します。 TextOut()で書いた文字は印刷プレビューでちゃんと表示されましたが、以下のようにして取りこんだ画像を印刷プレビューで見ても何も表示されません。 どうしたら印刷できるようになりますか? void CXxxView::OnDraw(CDC* pDC) { CXxxDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: この場所にネイティブ データ用の描画コードを追加します。 CDC myDC; CBitmap myBMP; myBMP.LoadBitmap(IDB_BITMAP3); myDC.CreateCompatibleDC(pDC); CBitmap* oldBMP=myDC.SelectObject(&myBMP); pDC->BitBlt(10,10,60,100,&myDC,0,0,SRCCOPY); myDC.SelectObject(oldBMP); }

  • ビューにビットマップファイルを描画する方法

    MFCのプログラムで(マルチウィンドウ)ビュー上に指定したビットマップファイルをオープンして描画したいと思ってます。 Bitmapリソースを指定して描画する方法はわかりましたが、ビットマップファイル名を指定して、そのファイルをオープンしてビュー上に描画する方法はどのようすればよいのでしょうか? 今は以下のようにOnDraw()内で以下のように実装しています。 -------------------------------------------------------- CBitmap kaitaGazou; kaitaGazou.LoadBitmap(IDB_BITMAP1); CDC MemDC; MemDC.CreateCompatibleDC(pDC); CBitmap *pTmpBitmap; pTmpBitmap = MemDC.GetCurrentBitmap(); MemDC.SelectObject(&kaitaGazou); pDC->BitBlt(0, 0, 100, 100, &MemDC, 10, 10, SRCCOPY); MemDC.SelectObject(pTmpBitmap); kaitaGazou.DeleteObject(); --------------------------------------------------------

  • LoadBitmapでCStringを使いたい

    VC++.NETでMFCアプリケーションを作っています。 CBitmap::LoadBitmapの定義では  BOOL LoadBitmap(LPCTSTR lpszResourceName); とあるのですが、リソースネームはCString型の変数では指定できないのでしょうか? ビットマップリソースがIDB_BMP1~IDB_BMP5まであり、状況により表示する画像を切り替える、ということをしたいのですが。   (略)  int n=1;  CString fname;  CBitmap bmp;  fname.Fromat("IDB_BMP%d",n);  bmp.LoadBitmap(fname);  pOldbmp = myDC.SelectObject(&bmp);  pDC->BitBlt(0, 300, 50, 77, &myDC, 0, 0, SRCCOPY);   (略) とすると画像が読み込まれません。 なお、LoadBitmapのfnameの部分を IDB_BMP1 と置き換えれば、画像は正常に表示できます。 MFC自体が初めてなので、分かりやすいご説明をいただけると嬉しいです。

  • LoadBitmapについて

    環境 WIN98 VC++6.0 MFC にて 下記のようにbmp.LoadBitmap(IDB_BITMAP1);を2度続けるとダウンしますがどうしてですか? void CAdvancedRgnDlg::OnPaint() { CBitmap bmp; bmp.LoadBitmap(IDB_BITMAP1); bmp.LoadBitmap(IDB_BITMAP1);//2度続けるとダウンする CDialog::OnPaint(); }

  • ちらつきについて

    ゲームをつくっているのですが、画面がちらつくのが気になり、直そうと、ネットで調べたのですが、裏画面に一度、ビットマップを表示させて、それをデバイスコンテキストに転送する?ってやりかたがよくわかりません。 CMyFrameWnd::OnPaint(){ CPaintDC dc(this); CDC MemDC; CBitmap bitmap1; bitmap1.LoadBitmap("IDB_BITMAP1"); ...略 for(j=0;j<30;j++){ for(k=0;k<30;k++){ MemDC.SelectObject(&bitmap1); dc.Blt(j*32,k*32,32,32,&MemDC,0,0,SRCCOPY); } } } 見たいな感じです。なにぶんc,c++始めたばっかりでデバイスコンテキストとかもよくわかってないんでわかりやすい説明お願いします。

  • オブジェクトの削除について

    環境 WIN98 VC++6.0 MFC にて オブジェクトを使い終わってから削除している場合としていない場合が有るのですが、どうしてなのですか? 作ったオブジェクトはなんでもかんでも削除したほうが無難な気がしますが、本にのっているコードで削除してない場合も良く見かけます。 <削除していない>//著名な本のコード void Cxxx::OnDraw(CDC* pDC) {  CBitmap bmp;  bmp.LoadBitmap(nID);  略  //bmp.DeleteObject(); //■この記述が無い } <削除している>//ネット上でみかけたコード void CMainFrame::_SetBmp(CWnd* pBox,int nID,int  width,int height) // 単品 {  CDC* pDC=pBox->GetDC();  CDC memDC;  CBitmap bmp;  bmp.LoadBitmap(nID);  memDC.CreateCompatibleDC(pDC);  CBitmap* pOldBmp=memDC.SelectObject(&bmp);  pDC->BitBlt(0,0,width,height,&memDC,0,0,SRCCOPY);  memDC.SelectObject(pOldBmp);  bmp.DeleteObject();  memDC.DeleteDC(); }

  • ビットマップを表示させる(MFC)

    CDC::SelectObject を使用して、 ビットマップをメモリDCに割り当てたあと、 CDC::BitBltで画面に表示しています。 すでに、画面に表示されているビットマップを残したまま、 2枚目のビットマップを表示したいのですが、 2枚目を表示すると同時に1枚目のビットマップが消えてしまいます。 (当然ですが。。。) 1枚目(すでに表示させているビットマップ)を残し、 2枚目のビットマップを同じ画面に表示するには、 どうすればよいでしょうか?

  • クライアント領域をCBitmapに取り込みたい

    VC6.0MFCで クライアント領域(みたまま)を CBitmapに取り込みたいのですがどうすればよいのでしょうか? ためしにダイアログの領域をクリップボードに取り込むコード OnPaint書いたのですが真っ黒の画像しか取り込めていませんでした。 根本的に使うAPIが違うのでしょうか? void CCaptureDlg::OnPaint() {  CPaintDC dc(this); // 描画用のデバイス コンテキスト  CRect cr;  GetClientRect(&cr);  dc.TextOut(0,0,"テスト");  CDC* pDC = new CDC();  pDC->CreateCompatibleDC(&dc);  CBitmap img;  img.CreateCompatibleBitmap(pDC, cr.Width(), cr.Height());  OpenClipboard();  ::EmptyClipboard();  ::SetClipboardData(CF_BITMAP, img.GetSafeHandle());  ::CloseClipboard();  pDC->DeleteDC();  delete pDC;  CDialog::OnPaint(); }

  • VC++にてボタン作成について(長文)

    VC++にて実行画面でボタンを表示させたいのですが、(表示するのはボタンだけではありません。)どのようにソースを書いたらいいのでしょう?Bitmapだったら、Viewクラスで ------------------------------------------------ CDC myDC; CBitmap newBitmap; CBitmap *pOldBitmap; newBitmap.LoadBitmap(画像の名前); myDC.CreateCompatibleDC(pDC); pOldBitmap=myDC.SelectObject(&newBitmap); pDC->BitBlt(10,10,320,240,&myDC,0,0,SRCCOPY); myDC.SelectObject(pOldBitmap); ------------------------------------------------ こんな感じかと思いますが、ボタンだったらどういった感じでソースを書いたらよいのでしょうか? また、こういったことを自分で調べたい場合には「ヘルプ」で何をキーワードにして検索したらよいのでしょう? VCを独学するのにどこか良いサイトはありますか?(できたら「ボタン」について詳しく説明してくれるサイトがいいです。) VCはほとんど素人なので簡単なことなのかも知れませんが、まったく分かりません。 ご存知の方、ご教授願います。