- ベストアンサー
MFCのダブルバッファリングを用いた画面切り替えプログラムの修正方法
- MFCのダブルバッファリングを用いて画面を切り替えるプログラムを作成したが、画面がちらつく問題が発生している。修正方法を教えてください。
- CgraphViewのOnDraw関数において、ダブルバッファリングを行っているが、画面がちらついてしまう。どう修正すればよいか教えてください。
- 画面のちらつきを解消するためには、CgraphViewのOnDraw関数でのダブルバッファリングを改善する必要がある。具体的な修正方法を教えてください。
- みんなの回答 (11)
- 専門家の回答
質問者が選んだベストアンサー
>ソースコードをもう一度掲載します >(1)をどの場所で行うかは今の所わからない現状です。 まったくNo.2内容を読み取れてませんね。 (2)に答えが書いてあります。 (a)裏画面の方を塗りつぶして (b)裏画面の描画全部終わってから (c)表画面に転送する この(a)(b)(c)をちゃんと実践してますか? それぞれ実勢しているソースコードを書きだして下さい。 あと少なくとも(b)に反している部分があります。 else if( draw_state == 1 ) { CRect myRect; GetClientRect( myRect ); pDC->FillSolidRect( myRect, RGB( 255, 255, 255 ) ); } この処理が必要な理由も私にはわかりませんが、pDCで無いことは確かです。 それとグラフを表画面に直接書くとチラつくと思います。 なぜ裏画面に書かないのでしょうか? これも(b)に反してます。 あちこちから何も考えずにサンプルコードをコピーしてくるのは止めて下さい。
その他の回答 (10)
- ygoos_ygoos
- ベストアンサー率50% (1/2)
説明が正しいか判別不能なのでOnDrawは全て掲載して下さい。 ちなみに(1)を排除するという言い方はマズかったですね。 形を変えて何処かで行わないと行けません。 それはどの様な形でしょうか?
補足
ソースコードをもう一度掲載します (1)をどの場所で行うかは今の所わからない現状です。 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); 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(); int x0=50, y0=450, xsp=700, ysp=400, xp, yp ; // float xmax, ymax; int DataN=pDoc->DN, i; //pDC->SetTextColor(RGB(0,0,255)); //pDC->TextOut(0,0,"Title");//グラフタイトル CPen Pen1(PS_SOLID,1,RGB(0,0,0)); //ペンの初期化 CPen Pen2(PS_SOLID,2,RGB(0,0,0)); CPen* OldPen=pDC->SelectObject(&Pen1); //ペンの変更 if(DataN!=0){ pDC->SelectObject(Pen2); pDC->MoveTo(x0,y0); pDC->LineTo(x0+xsp,y0); pDC->MoveTo(x0,y0); pDC->LineTo(x0 ,y0-ysp); for(i=0;i<=DataN;i++){ xp=(int)(x0+pDoc->Dx[i]/100.0*xsp); yp=(int)(y0-pDoc->Dy[i]/100.0*ysp); if(i==0) pDC->MoveTo(xp,yp); else pDC->LineTo(xp,yp); } } pDC->SelectObject(OldPen); }
- ygoos_ygoos
- ベストアンサー率50% (1/2)
>(1)はわかりませんが、 直し方がわからないのは問題点が分からないからです。 (1)と(2)はセットで語られているのは分かりますか? (1)の問題点を排除し、(2)の方法で修正するのです。 さて、何処を排除しますか? >(2)は裏画面を表画面に送る処理を全ての描画が終わってからのところに持っていったのですが余計にちらついてしまいました 元から最後の処理にあるようですが? 最新のコードを掲載して下さい。
補足
(1)では 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)); の部分を排除しました //裏画面bkDCにおいて、すべての描画を行った後 //裏画面を表画面に送る pDC->BitBlt(0, 0, rc.right, rc.bottom, &bkDC, 0, 0, SRCCOPY); bkDC.SelectObject(pOldBitmap); //裏画面を消去 bkBMP.DeleteObject(); bkDC.DeleteDC(); の後にグラフを描画するコードが書かれていて その後ろに持っていったということです
- ygoos_ygoos
- ベストアンサー率50% (1/2)
では、(1)と(2)は何処を直すべきでしょう? 問題点は理解できたんですよね。
補足
(1)はわかりませんが、(2)は裏画面を表画面に送る処理を全ての描画が終わってからのところに持っていったのですが余計にちらついてしまいました
- ygoos_ygoos
- ベストアンサー率50% (1/2)
そこ以前の問題です。No.2の内容に(1)(2)と番号を振ったので質問全部に回答して下さい。 (1)そこで塗ったらCgraphView::OnEraseBkgnd()で背景塗らずに返した意味がありませんか? 塗りつぶした瞬間、画面がチラつきませんか?? 質問:(1)が問題としているのは何処で何故でしょうか? (2) ダブルバッファリングしているのであれば、 「裏画面の方を塗りつぶして、裏画面の描画全部終わってから表画面に転送する」 というのが狙っている動作ではありませんか? 質問:(2)の代案はなぜ検討されていないのでしょうか? ># この場合クライアント領域全部の転送が必要ではありますが。 現状転送されてると思います。 >まぁ、ついでに言うなら裏画面用のデバイスコンテキストやビットマップの作成は先にやっておいて、WM_PAINTのたびに生成/破棄のコストを払うのも…>というのはありますが。 ># WM_SIZEなどいくつかのメッセージに対応してデバイスコンテキストの再作>成などが必要になったりはしますけど。 これは難易度が高いので、それ以前の事ができてからです。 ちなみにOnDrawはWM_PAINTメッセージの結果呼び出されるのでOnDrawと言い換えて良いでしょう。
補足
(1)が問題にしているのは背景を塗らずに返しているのに 再度塗り変えているため (2)に関しては読み間違えていて、今理解できました
- ygoos_ygoos
- ベストアンサー率50% (1/2)
No.2の何処の部分が分からないんでしょう? そしてNo.2の回答が良く分からないにもかかわらず分からない点を何故質問しなかったのでしょうか? >ダイアログで背景を変える設定をなくしても画面がちらつくのですが >それはどうしてでしょうか No.2の自分なりの理解として、この質問になったということですか? それとも分らないことは無視したのでしょうか? どのぐらい理解しているか知りたいのでNo.2の内容を解説してみて下さい。
補足
No.2の ># この場合クライアント領域全部の転送が必要ではありますが。 >まぁ、ついでに言うなら裏画面用のデバイスコンテキストやビットマップの作成は先にやっておいて、WM_PAINTのたびに生成/破棄のコストを払うのも…>というのはありますが。 ># WM_SIZEなどいくつかのメッセージに対応してデバイスコンテキストの再作>成などが必要になったりはしますけど。 の部分が理解できていません。ダブルバッファリングは仮想的なデバイスコンテキストに一度描画処理を行い、一通り描画が終わった段階で実際のデバイスコンテキストに描画結果を転送していることは理解しています
- ygoos_ygoos
- ベストアンサー率50% (1/2)
>ちらつかないようにするにはどうしたら良いでしょうかね 既にNo.2で答えが書かれています。今までの回答を全部見なおして良く考えて質問して下さい。 Wr5さんなんか同じ答えを繰り返し書いているわけですから疲れ果てていると思います。こんな事を繰り返していると回答者が誰もいなくなりますよ。
補足
見てもよく分からないので質問させてもらっているのですが OnPaintの中に書けばいいのですか
- ygoos_ygoos
- ベストアンサー率50% (1/2)
>そのときとはどの時のことを言っているんでしょうか >draw_stateは最初の画面では0、Startというテキストをクリックしたとき1になるようになっています 文脈的に「ダイアログで背景を変える設定をなくしても画面がちらつくのですが」がその時としか受け取れないですよ。 つまりdraw_stateが1ならチラついて当たり前です。なぜなら、そうプログラムを組んでいるのですから。
補足
ちらつかないようにするにはどうしたら良いでしょうかね
- Wr5
- ベストアンサー率53% (2173/4061)
>ダイアログで背景を変える設定をなくしても画面がちらつくのですが そのときのdraw_stateの値はいくつですか? 1だったらpDCに対して塗りつぶししているんですからチラつくと思いますが。 # 「どこで?」なんて言わないですよね?
補足
そのときとはどの時のことを言っているんでしょうか draw_stateは最初の画面では0、Startというテキストをクリックしたとき1になるようになっています
- Wr5
- ベストアンサー率53% (2173/4061)
>上の部分はダイアログで背景を変える設定です そこで塗ったらCgraphView::OnEraseBkgnd()で背景塗らずに返した意味がありませんか? 塗りつぶした瞬間、画面がチラつきませんか?? ダブルバッファリングしているのであれば、 「裏画面の方を塗りつぶして、裏画面の描画全部終わってから表画面に転送する」 というのが狙っている動作ではありませんか? # この場合クライアント領域全部の転送が必要ではありますが。 まぁ、ついでに言うなら裏画面用のデバイスコンテキストやビットマップの作成は先にやっておいて、WM_PAINTのたびに生成/破棄のコストを払うのも…というのはありますが。 # WM_SIZEなどいくつかのメッセージに対応してデバイスコンテキストの再作成などが必要になったりはしますけど。
補足
ダイアログで背景を変える設定をなくしても画面がちらつくのですが それはどうしてでしょうか
- Wr5
- ベストアンサー率53% (2173/4061)
>BOOL CgraphView::OnEraseBkgnd(CDC* pDC) >{ >return TRUE; >} は正しいとして…… >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)); が、なにをやっているのか説明できますか? その上で、 >bkDC.FillSolidRect(rc, RGB(255, 255, 255)); >pDC->FillSolidRect(myRect, RGB(255, 255, 255)); >pDC->BitBlt(0, 0, rc.right, rc.bottom, &bkDC, 0, 0, SRCCOPY); のそれぞれがどういう結果をもたらすのか理解できますか?
補足
>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)); 上の部分はダイアログで背景を変える設定です
補足
細かく説明していただきありがとうございます ちゃんとちらつかずに画面を表示させることができました。