• 締切済み

ダブルバッファについて

スタート画面にBitmapを用いたアニメーションを用いて、次の場面に移動したいのですが 実行すると画面がちかちかしてしまいます。どう直せばよいか教えてもらえると助かります プログラムはVisualStudio2008のMFCでやっています #include "stdafx.h" #include "graph.h" #include "graphDoc.h" #include "graphView.h" #ifdef _DEBUG #define new DEBUG_NEW #endif //全域変数 CDC bkDC; CBitmap bkBMP; #define ID_REDRAW 30 #define TIMER_MS_FPS 1000/30 #define ID_BITMAP 60 #define TIMER_MS_BITMAP 300 #include <math.h> int draw_state = 0; float mouse_x = -1.0, mouse_y = -1.0; // CgraphView IMPLEMENT_DYNCREATE(CgraphView, CView) BEGIN_MESSAGE_MAP(CgraphView, CView) // 標準印刷コマンド ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview) ON_COMMAND(ID_BK_WHITE, &CgraphView::OnBkWhite) ON_COMMAND(ID_BK_BLUE, &CgraphView::OnBkBlue) ON_COMMAND(ID_BK_PINK, &CgraphView::OnBkPink) ON_WM_TIMER() ON_WM_DESTROY() ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() // CgraphView コンストラクション/デストラクション CgraphView::CgraphView() : background_color(0) , draw_state(0) , Bmp_ID(0) { // TODO: 構築コードをここに追加します。 background_color = 0; int draw_state = 0; } CgraphView::~CgraphView() { } BOOL CgraphView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: この位置で CREATESTRUCT cs を修正して Window クラスまたはスタイルを // 修正してください。 return CView::PreCreateWindow(cs); } // CgraphView 描画 void CgraphView::OnDraw(CDC* pDC) { CgraphDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: この場所にネイティブ データ用の描画コードを追加します。 //ダブルバッファに関するコード CRect rc; GetClientRect(&rc); bkDC.CreateCompatibleDC(pDC); bkBMP.CreateCompatibleBitmap(pDC, rc.right, rc.bottom); bkDC.SelectObject(&bkBMP); //描画は、裏画面bkDCにおいて行う bkDC.FillSolidRect(rc, RGB(153, 204, 255)); int x, y, sx, sy; if(draw_state == 0) { bkDC.SetTextColor(RGB(255, 255, 255)); bkDC.TextOut(480, 580, _T("Start")); sx = 128; sy = 128; y = 340; x = 200; draw_school(x, y, sx, sy);//定義は省略 x = 400; draw_health(x, y, sx, sy);//定義は省略 x = 600; draw_environment(x, y, sx, sy);//定義は省略 } else if(draw_state == 1) { CRect myRect; GetClientRect(myRect); pDC->FillSolidRect(myRect, RGB(0, 0, 0)); } //裏画面を表画面に送る //pDC->BitBlt(0, 0, rc.right, rc.bottom, &bkDC, 0, 0, SRCCOPY); //裏画面を消去 bkBMP.DeleteObject(); bkDC.DeleteDC(); //実行画面のプログラムを省略    void CgraphView::OnInitialUpdate() { CView::OnInitialUpdate(); // TODO: ここに特定なコードを追加するか、もしくは基本クラスを呼び出してください。 bitmap[0].LoadBitmap(IDB_BITMAP1); bitmap[1].LoadBitmap(IDB_BITMAP2); bitmap[2].LoadBitmap(IDB_BITMAP3); bitmap[3].LoadBitmap(IDB_BITMAP4); bitmap[4].LoadBitmap(IDB_BITMAP5); bitmap[5].LoadBitmap(IDB_BITMAP6); //タイマーをスタート SetTimer(ID_BITMAP, TIMER_MS_BITMAP, NULL); //画面再描画のタイマーをスタートする SetTimer(ID_REDRAW, TIMER_MS_FPS, NULL); Bmp_ID = 0; } void CgraphView::OnTimer(UINT_PTR nIDEvent) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 if(nIDEvent == ID_BITMAP) Bmp_ID = (Bmp_ID+1) % 2; if(nIDEvent == ID_REDRAW) InvalidateRect(NULL, FALSE); CView::OnTimer(nIDEvent); } void CgraphView::OnDestroy() { CView::OnDestroy(); // TODO: ここにメッセージ ハンドラ コードを追加します。 KillTimer(ID_BITMAP); KillTimer(ID_REDRAW); } void CgraphView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 mouse_x = point.x; mouse_y - point.y; if(draw_state == 0) { if(mouse_x > 420 && mouse_y > 500) { draw_state = 1; } } CView::OnLButtonDown(nFlags, point); } //以下は関数の定義なので省略

  • tnk48
  • お礼率9% (7/76)

みんなの回答

回答No.7

> pOldBitmap = bkDC.SelectObject(&Bitmap); > bkDC.SelectObject(&bkBMP); この部分は、 pOldBitmap = bkDC.SelectObject(&bkBMP); でいいです。(当然、Bitmapは必要ありません) ちらつきの件は、最初回答にあるもう一つの部分が原因の可能性が高いです。

tnk48
質問者

補足

最初の回答とはWM_ERASEBACKGROUNDの部分ですよね

回答No.6

だから、元に戻してるんですか? 作成したビットマップを削除しても、元に戻るわけではありませんよ。

tnk48
質問者

補足

下記のように選択したビットマップを元に戻しましたがうまくいきませんでした //ダブルバッファに関するコード CRect rc; GetClientRect(&rc); bkDC.CreateCompatibleDC(pDC); bkBMP.CreateCompatibleBitmap(pDC, rc.right, rc.bottom); CBitmap Bitmap, *pOldBitmap; pOldBitmap = bkDC.SelectObject(&Bitmap); bkDC.SelectObject(&bkBMP); //裏画面を表画面に送る pDC->BitBlt(0, 0, rc.right, rc.bottom, &bkDC, 0, 0, SRCCOPY); bkDC.SelectObject(pOldBitmap); //裏画面を消去 bkBMP.DeleteObject(); bkDC.DeleteDC();

回答No.5

間違ってるから指摘してるんですが。 > 必ず元の(既定)オブジェクトに置き換えるべきです。 の部分を実行しているコードがあるなら、抜き出してみてください。

tnk48
質問者

補足

SelectObjectを使用しているのはbkDC.SelectObject(&bkBMP);だけだと思うのですが違いますか

回答No.4

デバイスコンテキストに選択された状態のビットマップを削除してしまうと、そのデバイスコンテキストはどうなるのでしょうか? また、SelectObjectの説明には > この関数は、指定されたのと同じタイプで、それまで選択されていたオブジェクトを返します。 > アプリケーションは新しいオブジェクトを使い終えたら、必ず元の(既定)オブジェクトに置き換 > えるべきです。 http://msdn.microsoft.com/ja-jp/library/cc410576.aspx という記述がありますが、その通りにしていますか? このようなことは、デバイスコンテキストを使った描画の解説には、必ず書かれているはずの事柄です。だから、もう一度確認しましょうと言っているのです。

tnk48
質問者

補足

使い方は間違っていないと思うのですがどこかおかしいですかね

回答No.3

ビットマップに限らず、デバイスコンテキストに選択したGDIオブジェクト(ペン・ブラシ・フォントなど)は、使用し終わったら選択解除する(元々デバイスコンテキストに選択されていたオブジェクトを選択しなおす)必要があります。 デバイスコンテキストを使用した描画の解説では、必ず出てくる部分なので、もう一度確認してみてください。

tnk48
質問者

補足

選択したGDIオブジェクトはDeleteObject()を使ってちゃんと削除しているのですがどこが違うのですか

回答No.2

ビットマップを削除している部分と、具体的に指摘してるんですが。 どのコードかまで指摘しなければならないとすると、あなたがこれらのコードを理解していないということになります。それでは修正は難しいでしょう。

tnk48
質問者

補足

ビットマップを削除する部分は分かるのですが、選択したビットマップを解除している部分がどういうことなのか分かりません

回答No.1

選択したビットマップを解除せずに削除しようとしてたり、問題が結構あると思います。 もう一度、描画コードの基本を確認してみては? bkDC、bmBMPは関数内で定義しても問題ないと思いますし。 あと、WM_ERASEBACKGROUNDをどう処理しているかも確認したほうがいいでしょう。

tnk48
質問者

補足

具体的にどの部分を修正すればよいか 上のプログラムの場所で教えてもらえますか?

関連するQ&A

  • MFCプログラミング

    MFCのダブルバッファリングを用いて画面を切り替えるプログラムを作ったのですが 画面がちらついてしまいます、どう修正すればよいか教えてください // CgraphView 描画 void CgraphView::OnDraw(CDC* pDC) { CgraphDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: この場所にネイティブ データ用の描画コードを追加します。 CRect myRect; GetClientRect(myRect); if(background_color == 0) pDC->FillSolidRect(myRect, RGB(255, 255, 255)); else if(background_color == 1) pDC->FillSolidRect(myRect, RGB(153, 204, 255)); else pDC->FillSolidRect(myRect, RGB(255, 153, 204)); //ダブルバッファに関するコード CRect rc; GetClientRect(&rc); bkDC.CreateCompatibleDC(pDC); bkBMP.CreateCompatibleBitmap(pDC, rc.right, rc.bottom); CBitmap Bitmap, *pOldBitmap; pOldBitmap = bkDC.SelectObject(&bkBMP); //これから、すべての描画は、裏画面bkDCにおいて行う bkDC.FillSolidRect(rc, RGB(255, 255, 255)); int x, y, sx, sy; if(draw_state == 0) { bkDC.SetTextColor(RGB(0, 0, 0)); bkDC.TextOut(400, 500, _T("Start")); sx = 128;//表示するビットマップの横の大きさ sy = 128;//表示するビットマップの縦の大きさ y = 300;//表示するビットマップの左上の頂点のy座標 x = 50; draw_school(x, y, sx, sy); x = 200; draw_health(x, y, sx, sy); x = 350; draw_environment(x, y, sx, sy); } else if(draw_state == 1) { CRect myRect; GetClientRect(myRect); pDC->FillSolidRect(myRect, RGB(255, 255, 255)); } //裏画面bkDCにおいて、すべての描画を行った後 //裏画面を表画面に送る pDC->BitBlt(0, 0, rc.right, rc.bottom, &bkDC, 0, 0, SRCCOPY); bkDC.SelectObject(pOldBitmap); //裏画面を消去 bkBMP.DeleteObject(); bkDC.DeleteDC(); void CgraphView::OnInitialUpdate() { CView::OnInitialUpdate(); // TODO: ここに特定なコードを追加するか、もしくは基本クラスを呼び出してください。 bitmap[0].LoadBitmap(IDB_BITMAP1); bitmap[1].LoadBitmap(IDB_BITMAP2); bitmap[2].LoadBitmap(IDB_BITMAP3); bitmap[3].LoadBitmap(IDB_BITMAP4); bitmap[4].LoadBitmap(IDB_BITMAP5); bitmap[5].LoadBitmap(IDB_BITMAP6); Bmp_ID = 0; //タイマーをスタート SetTimer(ID_BITMAP, TIMER_MS_BITMAP, NULL); //画面再描画のタイマーをスタートする SetTimer(ID_REDRAW, TIMER_MS_FPS, NULL); Bmp_ID = 0; } void CgraphView::OnTimer(UINT_PTR nIDEvent) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 if(nIDEvent == ID_BITMAP) Bmp_ID = (Bmp_ID+1) % 2; if(nIDEvent == ID_REDRAW) InvalidateRect(NULL, FALSE); CView::OnTimer(nIDEvent); } void CgraphView::OnDestroy() { CView::OnDestroy(); // TODO: ここにメッセージ ハンドラ コードを追加します。 KillTimer(ID_BITMAP); KillTimer(ID_REDRAW); } void CgraphView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 mouse_x = point.x; mouse_y = point.y; if(draw_state == 0) { if(mouse_x > 400 && mouse_y > 500) { draw_state = 1; } } CView::OnLButtonDown(nFlags, point); } BOOL CgraphView::OnEraseBkgnd(CDC* pDC) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 return TRUE; //return CView::OnEraseBkgnd(pDC); }

  • if文の判定について

    <環境> WIN98 VC++6.0 MFC  ダイアログベースにて 以下コードにて、タイマーによる変数nの変化に伴い絵1と絵2が切り替わっています。 int n; void CxxxDlg::OnPaint() { 略 m_p9[0].LoadBitmap(IDB_BITMAP1); m_p9[1].LoadBitmap(IDB_BITMAP2); tempDC9.SelectObject(&m_p9[n]); 略 } void CxxxDlg::OnTimer(UINT nIDEvent) { n=n+1; if(n>=2){ n=0; } Invalidate();   CDialog::OnTimer(nIDEvent); } ところがコードの一部を以下のように変更すると、 if文で正しく判定できなくなります。 どうしてなのでしょうか? if (n=0){ m_p9[0].LoadBitmap(IDB_BITMAP1); } m_p9[1].LoadBitmap(IDB_BITMAP2);

  • 画像の印刷について

    環境は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); }

  • VC++のOnDraw()関数で、ボールを動かす

    下記のように、VC++のOnDraw()関数において、ウィンドウ上でボールを上下に 動かせたいのですが、動きません。VC++のバージョンは9.0です。(Visual Studio 2008) どういうふうに書けば動きますか? ------------------------------------------------------------------------- void CControllGameView::OnDraw(CDC* pDC) { Bitmap2.LoadBitmap(IDB_BITMAP2); // ボール pOldBitmap = MemDC.SelectObject(&Bitmap2); // 転送前のビットマップ領域を退避 GetClientRect(&rect); // ウィンドウのサイズをrectに記憶 pDC->BitBlt((rect.right-42)/2, rect.top+50, 42, 41, &MemDC, 0, 0, SRCCOPY); // ビット単位でビットマップ画像を転送 int z = rect.bottom + 50; // ボールのy座標の初期値 while(z < rect.top){ pDC->MoveTo((rect.right-42)/2, z+=1); } MemDC.SelectObject(pOldBitmap); // 元に戻す ReleaseDC(pDC); }

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

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

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

    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(); --------------------------------------------------------

  • ローカル関数についてお願いします

    VC++プログラムです ボタン1,2は正常に動いたので割愛させていただきます この文をビルドしたらエラーがでました void CparaparaDlg::OnBnClickedButton3(){ { CPaintDC dc (this); CRect sikaku; GetClientRect (sikaku); int n; CBitmap gazou[2]; int CparaparaDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { gazou[0].LoadBitmap(IDB_BITMAP1); gazou[1].LoadBitmap(IDB_BITMAP2); n = 1; SetTimer(1, 200, NULL); return 0; } void CparaparaDlg::OnTimer(UINT nIDEvent) { n = n + 1; if(n >= 3){ n = 1; } Invalidate(); if(n == 1){ OnBnClickedButton1(); } else if (n == 2){ OnBnClickedButton2(); } } } error C2601: 'CWnd::OnCreate' : ローカル関数の定義が正しくありません。 c:\Documents and Settings\mizuno\My Documents\Visual Studio error C2601: 'CWnd::OnTimer' : ローカル関数の定義が正しくありません。 というエラーが出ました・・・ どこをどう手直しすればよいのか教えていただける方、お願いします 関数についても教えていただけると幸いです

  • 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()に処理が % 移りません。

  • 画像表示について

    画像を表示させたいのですがうまくいきません。 途中まで打ってみたのでご意見お願いします。 (リソースから読み込んで表示させる方法) 環境:MicrosoftVisualC++ SDK ******省略********* case WM_PAINT:   hdc = BeginPaint(hWnd,&ps);   //ビットマップリソースハンドルの取得   hBmp = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP1));   if(hBmp == NULL){     MessageBox(hWnd,"ファイルの読み込みに失敗しました。","エラー",MB_ICONWARNING | MB_OK);     exit(1);   }   //ビットマップの大きさの情報取得   GetObject(hBmp,(int)sizeof(BITMAP),&bmp_info);   w = bmp_info.bmWidth;   h = bmp_info.bmHeight;   hdc_mem = CreateCompatibleDC(hdc);   SelectObject(hdc_mem,hBmp);   BitBlt(hdc,0,0,w,h,hdc_mem,0,0,SRCCOPY);   DeleteDC(hdc_mem);   DeleteObject(hBmp);   EndPaint(hWnd,&ps);   break; ******リソース(img.rc)****** // // Bitmap // IDB_BITMAP1 BITMAP DISCARDABLE "bitmap1.bmp" #ifdef APSTUDIO_INVOKED

  • Visual Studioのタイマ処理を使って描画を行うプログラムを

    Visual Studioのタイマ処理を使って描画を行うプログラムを 作成したのですがうまくいきません. プログラムの開発環境はWindows XP SP2でVC++6.0 外部に接続したセンサからのデータを50Hzで サンプリングして そのデータを元に描画を行う予定なのですが計測時間が100秒を超えると 異常終了してしまいます. 原因がよく分かりません. どうしたらよいのでしょうか? void CMyDlg::OnSamplingStart() { i=0; // サンプリング用タイマ開始 //なぜか12にするとちょうど50Hzでサンプリングする SetTimer(1,12,NULL); // 0.02秒毎タイマ割り込み,50Hz } void CMyDlg::OnTimer(UINT nIDEvent) { /* ここで,センサからのデータをサンプリングし,いろいろな計算をする. */ CDC* pDC=m_pict.GetDC(); CRect myRECT; m_pict.GetClientRect(myRECT); pDC->FillSolidRect(myRECT, RGB(255,255,255)); CPen BlueBoldPen,*OldBlueBoldPen; BlueBoldPen.CreatePen(PS_SOLID,5,RGB(0,0,255)); OldBlueBoldPen=pDC->SelectObject(&BlueBoldPen); pDC->MoveTo((int)(X0/10),(int)(Y0/10)); pDC->LineTo((int)(L3_x[i]/10),(int)(L3_y[i]/10)); pDC->LineTo((int)(C7_x[i]/10),(int)(C7_y[i]/10)); // ペンを元に戻す pDC->SelectObject(OldBlueBoldPen); BlueBoldPen.DeleteObject(); m_time=(double)i/50; UpdateData(FALSE); i=i+1; CDialog::OnTimer(nIDEvent); } 計測終了はボタンを押して終了します. どうが具体的な解決策を教えてください.

専門家に質問してみよう