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);
}
No.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)に反してます。
あちこちから何も考えずにサンプルコードをコピーしてくるのは止めて下さい。
No.10
- 回答日時:
説明が正しいか判別不能なので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);
}
No.9
- 回答日時:
>(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();
の後にグラフを描画するコードが書かれていて
その後ろに持っていったということです
No.7
- 回答日時:
そこ以前の問題です。
No.2の内容に(1)(2)と番号を振ったので質問全部に回答して下さい。(1)そこで塗ったらCgraphView::OnEraseBkgnd()で背景塗らずに返した意味がありませんか? 塗りつぶした瞬間、画面がチラつきませんか??
質問:(1)が問題としているのは何処で何故でしょうか?
(2)
ダブルバッファリングしているのであれば、
「裏画面の方を塗りつぶして、裏画面の描画全部終わってから表画面に転送する」
というのが狙っている動作ではありませんか?
質問:(2)の代案はなぜ検討されていないのでしょうか?
># この場合クライアント領域全部の転送が必要ではありますが。
現状転送されてると思います。
>まぁ、ついでに言うなら裏画面用のデバイスコンテキストやビットマップの作成は先にやっておいて、WM_PAINTのたびに生成/破棄のコストを払うのも…>というのはありますが。
># WM_SIZEなどいくつかのメッセージに対応してデバイスコンテキストの再作>成などが必要になったりはしますけど。
これは難易度が高いので、それ以前の事ができてからです。
ちなみにOnDrawはWM_PAINTメッセージの結果呼び出されるのでOnDrawと言い換えて良いでしょう。
この回答への補足
(1)が問題にしているのは背景を塗らずに返しているのに
再度塗り変えているため
(2)に関しては読み間違えていて、今理解できました
No.6
- 回答日時:
No.2の何処の部分が分からないんでしょう?
そしてNo.2の回答が良く分からないにもかかわらず分からない点を何故質問しなかったのでしょうか?
>ダイアログで背景を変える設定をなくしても画面がちらつくのですが
>それはどうしてでしょうか
No.2の自分なりの理解として、この質問になったということですか?
それとも分らないことは無視したのでしょうか?
どのぐらい理解しているか知りたいのでNo.2の内容を解説してみて下さい。
この回答への補足
No.2の
># この場合クライアント領域全部の転送が必要ではありますが。
>まぁ、ついでに言うなら裏画面用のデバイスコンテキストやビットマップの作成は先にやっておいて、WM_PAINTのたびに生成/破棄のコストを払うのも…>というのはありますが。
># WM_SIZEなどいくつかのメッセージに対応してデバイスコンテキストの再作>成などが必要になったりはしますけど。
の部分が理解できていません。ダブルバッファリングは仮想的なデバイスコンテキストに一度描画処理を行い、一通り描画が終わった段階で実際のデバイスコンテキストに描画結果を転送していることは理解しています
No.2
- 回答日時:
>上の部分はダイアログで背景を変える設定です
そこで塗ったらCgraphView::OnEraseBkgnd()で背景塗らずに返した意味がありませんか?
塗りつぶした瞬間、画面がチラつきませんか??
ダブルバッファリングしているのであれば、
「裏画面の方を塗りつぶして、裏画面の描画全部終わってから表画面に転送する」
というのが狙っている動作ではありませんか?
# この場合クライアント領域全部の転送が必要ではありますが。
まぁ、ついでに言うなら裏画面用のデバイスコンテキストやビットマップの作成は先にやっておいて、WM_PAINTのたびに生成/破棄のコストを払うのも…というのはありますが。
# WM_SIZEなどいくつかのメッセージに対応してデバイスコンテキストの再作成などが必要になったりはしますけど。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
見学に行くとしたら【天国】と【地獄】どっち?
みなさんは、一度だけ見学に行けるとしたら【天国】と【地獄】どちらに行きたいですか? 理由も聞きたいです。
-
【大喜利】【投稿~1/9】 忍者がやってるYouTubeが炎上してしまった理由
【お題】・忍者がやってるYouTubeが炎上してしまった理由
-
モテ期を経験した方いらっしゃいますか?
一生に一度はモテ期があるといいますが、みなさんどうですか? いまがそう! という方も、「思い返せばこの頃だったなぁ」という方も、よかったら教えて下さい。
-
あなたの人生で一番ピンチに陥った瞬間は?
これまでの人生で今振り返ると「あの時、1番ピンチだったなぁ...」という瞬間はありますか?
-
集中するためにやっていること
家で仕事をしているのですが、布団をはじめ誘惑だらけでなかなか集中できません。
-
画面を強制的に再描画させる方法
C言語・C++・C#
-
MFCのワーカースレッドとUIスレッドの使い分け
C言語・C++・C#
-
MFCのCListCtrlでスクロールを検出
C言語・C++・C#
-
-
4
CStringからchar*への型変換について教えてください。
C言語・C++・C#
-
5
UpdateData( FALSE); による文字列データの表示更新(VC++6.0)
C言語・C++・C#
-
6
VC++スレッドの正しい終了のさせかた
C言語・C++・C#
-
7
リストビューのスクロールバーを非表示にしたい
C言語・C++・C#
-
8
MFCでOnPaintのタイミング
C言語・C++・C#
-
9
MFCのコントロールにUTF-8の文字を表示したい
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・あなたの人生で一番ピンチに陥った瞬間は?
- ・初めて見た映画を教えてください!
- ・今の日本に期待することはなんですか?
- ・【大喜利】【投稿~1/31】『寿司』がテーマの本のタイトル
- ・集中するためにやっていること
- ・テレビやラジオに出たことがある人、いますか?
- ・【お題】斜め上を行くスキー場にありがちなこと
- ・人生でいちばんスベッた瞬間
- ・コーピングについて教えてください
- ・あなたの「プチ贅沢」はなんですか?
- ・コンビニでおにぎりを買うときのスタメンはどの具?
- ・おすすめの美術館・博物館、教えてください!
- ・【お題】大変な警告
- ・【大喜利】【投稿~1/20】 追い込まれた犯人が咄嗟に言った一言とは?
- ・洋服何着持ってますか?
- ・みんなの【マイ・ベスト積読2024】を教えてください。
- ・「これいらなくない?」という慣習、教えてください
- ・今から楽しみな予定はありますか?
- ・AIツールの活用方法を教えて
- ・最強の防寒、あったか術を教えてください!
- ・【大喜利】【投稿~1/9】 忍者がやってるYouTubeが炎上してしまった理由
- ・歳とったな〜〜と思ったことは?
- ・モテ期を経験した方いらっしゃいますか?
- ・好きな人を振り向かせるためにしたこと
- ・スマホに会話を聞かれているな!?と思ったことありますか?
- ・それもChatGPT!?と驚いた使用方法を教えてください
- ・見学に行くとしたら【天国】と【地獄】どっち?
- ・これまでで一番「情けなかったとき」はいつですか?
- ・この人頭いいなと思ったエピソード
- ・あなたの「必」の書き順を教えてください
- ・14歳の自分に衝撃の事実を告げてください
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
三菱GOTの画面切り替えについて
-
C# ログイン画面からメイン画面...
-
strutsで、JSP→アクションクラ...
-
C言語で今まで表示していた画面...
-
画像の縦横比固定の計算方法。
-
遷移元を判定したい!
-
system("cls")について
-
ホームページビルダーが遅い!...
-
サブミット後、自動的に画面を...
-
Strutsでのセッション保持方法...
-
JAVAのセッション変数の上書き...
-
C# Windowsフォーム全コントロ...
-
location.hrefでページ切替時の...
-
VBS/HTA:画面のサイズを取得す...
-
【JSP】input typeで入力された...
-
変数名とDBカラム名の関係性に...
-
モーダル画面の親をクリック時...
-
コマンドプロンプトが終了しない
-
java初心者です。 画面Aで情報...
-
ServletからHTMLページへの遷移...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
三菱GOTの画面切り替えについて
-
C言語で今まで表示していた画面...
-
C# ログイン画面からメイン画面...
-
Java-jspの画面入力値保持について
-
ASP.NET 画面遷移前の状態を保...
-
登録後、呼び出し元ページに戻...
-
location.hrefでページ切替時の...
-
Javascriptのhistory.back()が...
-
遷移元を判定したい!
-
画面を隠す・消す方法を教えて...
-
system("cls")について
-
画像の縦横比固定の計算方法。
-
非アクティブな画面を操作する...
-
javaのstrutsを使った画面遷移...
-
Strutsで画面遷移させない。
-
Javaプログラミングの質問にな...
-
アドレスバーに引数を表示させ...
-
ブラウザアドレスバーからのURL...
-
window.openした孫画面でSessio...
-
【JavaScriptわからない】1クリ...
おすすめ情報