• ベストアンサー

クライアント領域の保存

 初歩的な質問でごめんなさい。 VC.netのMFCで、OnLButtonDownで描画の処理をしているのですが、これだと画面を最小化したりするとクライアント領域に描画していたものが消去されてしまうので、画面全体のビットマップをメモリに保存しておきOnPaint関数でブロック転送すればよいと参考書に載っているのですが、このメモリに保存してブロック転送というのがうまくできません。  BitBltを使うのはわかるのですが、どうもうまくいきません。よろしければ、恐縮ですがソースを教えていただきたいです。お願いします。

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

  • ベストアンサー
  • thulala
  • ベストアンサー率63% (7/11)
回答No.1

CRect Rect; CDC memDC; CDC *pDC; CBitmap Bmp; CBitmap *oldBmp; void CPaintView::OnDraw(CDC* pDC) { CPaintDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; pDC->BitBlt(0,0,Rect.Size().cx,Rect.Size().cy,&memDC,0,0,SRCCOPY); // TODO: この場所にネイティブ データ用の描画コードを追加します。 } void CPaintView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO : ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 if(memDC==NULL) { pDC=GetDC(); GetClientRect(&Rect); Bmp.CreateCompatibleBitmap(pDC,Rect.Size().cx,Rect.Size().cy); memDC.CreateCompatibleDC(pDC); oldBmp=memDC.SelectObject(&Bmp); memDC.FillSolidRect(Rect,RGB(255,255,255)); ReleaseDC(pDC); } memDC.TextOut(point.x,point.y,"Hello"); Invalidate(); CView::OnLButtonDown(nFlags, point); } 大まかにはこんな感じだと思います。 WM_DESTROYの時にでも memDC、CBitmapの破棄を 適当に処理してください。

Giuseppe
質問者

補足

ありがとうございます。質問させて頂きたいのですが 最初の行のCRECT Rect;からCBitmap *OldBmp;までを Viewクラスのメンバー変数にし、 void CMyView::OnDestroy() { memDC.SelectObject(OldBmp); Bmp.DeleteObject(); memDC.DeleteDC(); CView::OnDestroy(); } を追加し、後はthulalaさんのご指摘どうり書かせていただいたのですが、ビルドは通っても実行するとフリーズするもしくはDebug Assertion Failedというウィンドウが表示されるます。OnPaintの中では何も書かなくてもよいのでしょうか? 恐縮ですが、もう一度アドバイス頂けないでしょうか?

その他の回答 (3)

  • thulala
  • ベストアンサー率63% (7/11)
回答No.4

Visual C++ 6.0 なら ClassView内の鍵マークのついた赤い関数を右クリックして削除を選択します。 Visual C++ .NET なら 表示-プロパティウインドウのプロパティでWM_****と たくさん書かれている項目があります。 そこで、追加のときと同様にクリックして、削除を選択します。

Giuseppe
質問者

補足

うまくいけました。 OnPaintは必要ないのですね。 お手数を御かけ致してすいません。 本当にありがとうございました。

  • thulala
  • ベストアンサー率63% (7/11)
回答No.3

**OnPaint関数は、イベントハンドらごと削除されましたか? //DEL void CPaintView::OnPaint() //DEL { //DEL CPaintDC dc(this); // 描画用のデバイス コンテキスト //DEL //DEL // TODO: この位置にメッセージ ハンドラ用のコードを追加してください //DEL //DEL // 描画用メッセージとして CView::OnPaint() を呼び出してはいけません //DEL } **こんな感じにしてもらえましたか? **ヘッダーも同様 memDC.CreateCompatibleDC(pDC);が初期化作業です。 LButtonを最初に押すときに何も初期化していないので、if(memDC==NULL){}の中の関数が実行されて、memDCなどが構築されます。2度目のLButtonDownで初期化作業が済んでいるのでif(memDC==NULL){}は無視されます。 memDC=NULL;とはしません。

  • thulala
  • ベストアンサー率63% (7/11)
回答No.2

メンバー変数にするならば、 CDC *pDCをCDC *mDCに変更して、 OnLButtonDown()内のpDCをmDCに変更してください。 void C***View::OnDraw(CDC* pDC) { *** //もしかすると、 if(memDC!=NULL) { pDC->BitBlt(0,0,Rect.Size().cx,Rect.Size().cy,&memDC,0,0,SRCCOPY); } } ウインドウが作成されたときに、まず描画がされます。 そのときに、memDCの中身が何も存在しないので BitBltできずにエラーを起こしたのかもしれません。 へんな書き方をしましたが、 すみません。 MFCのViewには、普通は OnDraw(CDC *pDC){}内部で描画します。 OnPaintには、何もしません。 コードを削除してください。

Giuseppe
質問者

補足

 度々すいません。本当にありがとうございます。  実行時のエラーは出なくなりましたが左クリックを押しても何もウィンドウに描画できません。あと、最初にmemDCをNULLで初期化しようとするとエラーが出て初期化できないのですが、どこでmemDCを初期化するのでしょうか?

関連するQ&A

  • 非クライアント領域への描画について

    非クライアント領域に文字を書こうとしました。 以下の(2)では書けますが、(1)では書いてくれません。 CPaintDCはクライアント領域でないとダメなのですか? void CMainFrame::OnPaint() { CPaintDC dc(this); // 描画用のデバイス コンテキスト dc.TextOut(0,0,"こんにちは"); ・・・(1) CDC* pDC = GetWindowDC(); pDC->TextOut(100,0,"こんにちは"); ・・・(2) 環境 WIN98 VC++6.0 MFC

  • クライアント領域を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(); }

  • クライアント領域のコントロールが描画されない

    WindowsXP / VC2005 / VC++ MFCにてダイヤログベースの画像ビューワの作成を行っています。 機能としては、独自形式のバイナリファイルをダイヤログへドラッグ&ドロップすることにより、 メモリに描画した画像をクライアント領域へ転送して表示します。 こちらが疑問点となるところなのですが、その際にもともと配置していた エディットボックスやスピンボタンなどのコントロールが消えてしまいます。 (見えなくてもボタンを押すことはできるので描画の問題と思われます) 1.なぜこのようなことが起こるのでしょうか? 2・また、コントロールを消さないためにはどうすればよいのでしょうか? 上記に関してご回答いただけると幸いです。 個人的な考えとしては、  1.クライアント領域を描画する際にコントロールを消してしまっている  2.再描画することによりコントロールは表示される(但し問題点としてクライアント領域を書き換える際にちらつく) です。 以下該当関数です //------------------------------------------------------------------------------ void CTestBitBltDlg::OnDropFiles(HDROP hDropInfo) { char acFileName[256]; SHORT sRet; memset(acFileName, 0, sizeof(acFileName)); DragQueryFile(hDropInfo, 0, acFileName, sizeof(acFileName)); memcpy( g_acSpriteFileName, acFileName, 256 - 1 ); CRect rc; GetClientRect(&rc); CClientDC dc(this); CDC dcMem; dcMem.CreateCompatibleDC(&dc); CBitmap bmp; bmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height()); CBitmap* pOldBmp = dcMem.SelectObject(&bmp); dcMem.FillSolidRect(&rc, RGB(0xC0, 0xC0, 0xC0)); // 本関数にてメインとなるメモリDCへの描画をおこなってます sRet = GetMemoryImage(g_acSpriteFileName, 0, &dcMem); if( sRet == FALSE ){ GetDefaultImage(&dcMem); } dc.BitBlt(0, 0, rc.Width(), rc.Height(), &dcMem, 0, 0, SRCCOPY); dcMem.SelectObject(pOldBmp); //InvalidateRect(FALSE); CDialog::OnDropFiles(hDropInfo); } //------------------------------------------------------------------------------ なお、OnEraseBkgnd関数においてはTRUEのみを返すようにしてます。

  • クライアント領域を再描画させない方法

    クライアント領域で左クリックを押したままマウスを移動させた時の処理 (WM_MOUSMOVE)として、マウスの位置情報を、 InvalidateRect(hWnd, NULL, FALSE); でWM_PAINTに送り、WM_PAINTで描画処理をさせます。 右クリックでの処理として、 case WM_RBUTTONDOWN:    InvalidateRect(NULL, NULL, TRUE);    return 0; とした時、WM_PAINTでは 右クリックによるWM_PAINTでは、クライアント領域を 再描画させない様にしたいのですが、 どのようにしたら良いのでしょうか? クライアント領域に描画されたのを再描画させないことで、 消したいのです。 MS VC++ & Win98 の環境で作成しています。

  • OnPaint() とOnDraw()の違いについて

    OnPaint内に記述した下記コードでビットマップが描画されますが、OnDraw内だと描画されません。 どうしてなのか教えてください。 お願いします。 void CAbcView::OnPaint() { HBITMAP myDIB; // ビットマップのハンドル HBITMAP oldDIB; HDC hDC; // デバイスコンテキストのハンドル HDC hCompatiDC; // メモリデバイスコンテキスト PAINTSTRUCT ps; // クライアント領域の描画に使う情報を保持 if(!m_BmpInfo) return; hDC = ::GetDC(m_hWnd);//これでもOK ::BeginPaint(m_hWnd,&ps); hCompatiDC = ::CreateCompatibleDC(hDC);//hDC); myDIB = ::CreateDIBitmap(hDC,&m_BmpInfo->bmiHeader, CBM_INIT,m_BmpImage,m_BmpInfo,DIB_RGB_COLORS); oldDIB=(HBITMAP)::SelectObject(hCompatiDC,myDIB); BitBlt(hDC,5,25,m_BmpInfo->bmiHeader.biWidth, m_BmpInfo->bmiHeader.biHeight,hCompatiDC,0,0,SRCCOPY); 略 } 環境 WIN98 VC++6.0 MFC にて

  • エディットコントロールを再描画させるには。

    CreateWindowEx()でエディットボックスを作り、配置して、 その背景のクライアント領域にビットマップを表示しようとしています。 ところが、再描画しようとした時に、BeginPaintで取得したHDCにBitBltでビットマップを表示するのは、問題なく動くのですが、 GetDCで取得したものに、BitBltを行うとエディットボックスが下に隠れてしまいます。(ビットマップで塗りつぶされてしまっています) それで、GetDCでも大丈夫なようにしたいのですが、 何か方法は無いでしょうか? どなたかお願いいたします。

  • MFCでOnPaintのタイミング

    Visual Studio 2008のMFCでOnPaint()が呼ばれるタイミングですが、 非表示の時など再描画が不要と思われるところで立て続けに 呼ばれているのが気になりました。 そのタイミングはどういう時でしょうか? といいますのも、ダイアログベースで OnPaint()の中でダブルッファリングを使用していくつかの処理をまとめて描画をしているのですが、 起動後数分後にCResourceExceptionで落ちてしまっていまして、 最小限の描画回数に済ませればそのようにはならないかと考えた次第です。 ※メンバにデバイスコンテキストとCBITAMAPを定義して使用しています。 BitBltするごとにDeleteObjectはしていますが・・・

  • Bitmapを重ね合わせる方法

    最近プログラミングを始めた初心者です。 環境はXP SP2 及びVC++6.0 です。 Win32APIのみを用いてプログラミングしております(MFCは使えません)。 宜しくお願い致します。 やりたいことは、あるビットマップを背景にして(bmpback.bmp)、その上に、bmpback.bmpよりサイズが小さいbmp1.bmpとbmp2.bmpを、WM_TIMERを使って交互に表示させる、です。 その際、WM_TIMER内でbmpback.bmpとbmp1.bmp(又はbmp2.bmp)を重ね合わせたbitmapを作成し、そのbitmapをWM_PAINT内でBitBltなどを用いてメモリDCからクライアント領域用のDCに転送して、ディスプレイに表示させたいと考えています。 検索したところ、以下のリンクに正に同じ質問があったのですが、難しくて理解出来ませんでした。 http://oshiete1.goo.ne.jp/qa1474735.html 回答者様が、良回答20ptで書かれている内容の、 >最終的に表示したい大きさのビットマップをメモリDCに割り当てて、 >そのメモリDCに対して10回のBitBltを行います。 の部分です。 最終的に表示したい大きさのビットマップ、というのが私の場合bmpback.bmpになると思いますが、例えばbmpback.bmpがSelectObject()でメモリDCに関連付けされているとして、そのメモリDCにbmp1.bmpをBitBltで転送する場合、bmp1.bmpに関連付けられるべきDC(デバイスコンテキスト)は何になるのでしょうか? (メモリDC→メモリDCかなあとも思ったのですが、それだとbmp1.bmpを紐付けした時点でbmpback.bmpが消えてしまうような気がして、ちょっと違うかなあと) 分かり辛い説明で申し訳ありませんが、知りたいことは、あるBitmapに別のBitmapをBitBltで転送して重ね合わせたい場合、コピー元のビットマップに関連付けるDCは何にすべきか、ということです。 本当は透過処理もしたいところですが、それは後で調べることにしてまずはBitBltで動作を見たいと思っています。 宜しくお願い致します。

  • WM_PAINTとBitBlt

    レベルはWindowsプログラミングを始めて1月半、それ以前にプログラミング経験はありません。 環境は、VC++6.0 WindowsXP SP2です。 WINAPIしか使えません(MFCは分かりません)。 宜しくお願い致します。 定期的に図形を動かすプログラムを副スレッドを用いて作りました。 副スレッドにはSleep(5msスリープ)を入れてあり、スレッドの最後にInvalidateRectを実行し、WM_PAINTを発行して再描画させているのですが、動作は所望な通りなものの、画面がちらついてしまいます。 所持している参考書を読むと、図形を動かす処理を直接ディスプレイに出すのではなく、メモリDCに一度出力し、その後BitBltでディスプレイに出力すればよい(ダブルバッファのことらしい?)、と書いてありました。 また、あるサイトには、WM_PAINTが実行されるとOnEraseBkgndが走るからちらつくとも書いてあり、何だか良く分かりません。 (別のサイトにはOnPaintが走るとか、OnPaintBackgroundが走ると書いてあり、何が本当なのか???) 自分の知りたいことは以下の通りです。 1)WM_PAINTで画面の再描画を行うと画面が何故チラつくのですか? また、ちらつかない様にする方法はあるのでしょうか? 2)BitBltを用いるとチラつかないのは何故でしょうか? 3)参考までにですが、メモリDCでBitBltで転送、以外に画面をチラつかせずに画面を更新させる方法はあるでしょうか? 色々サイトを探してみてのですが、断片的にしか書いておらず、結局自分が所望する回答は得られませんでした。 初心者レベルなので、分かりやすく説明して頂けると大変嬉しいです。 以上、宜しくお願い致します。

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

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