画面のチラツキを防ぐには – プログラミング – Home

画面のチラツキを防ぐには
 
通知
すべてクリア

[解決済] 画面のチラツキを防ぐには

固定ページ 1 / 2

Beginner
 Beginner
(@Beginner)
ゲスト
結合: 23年前
投稿: 63
Topic starter  

Win2K + VC++6.0 + MFCの練習のつもりでブロック崩しを書いています。
Delphiで書くと画面はちらつかないのですが、どうしても画面がちらつきます。
どうすれば良いか色々なスレッドを調べたのですが解決できません。ご教授お願いします。
void CBlockHitCPPDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォル
トの処理を呼び出してください
if (point.y>400)
{
CDC* pDC=GetDC();
CDC mDC;
CBitmap bmpRacket, *bmpOld;
CBitmap bmpRacket1, *bmpOld1;
bmpRacket.LoadBitmap(IDB_RACKET);
bmpRacket1.LoadBitmap(IDB_RACKET1);
//ラケットの前の位置を消去する
mDC.CreateCompatibleDC(pDC);
bmpOld1=mDC.SelectObject(&bmpRacket1);
pDC->BitBlt(oldMousePoint.x-80, oldMousePoint.y-30,
oldMousePoint.x+79, oldMousePoint.y+29,&mDC,0,0,SRCCOPY);
bmpOld=mDC.SelectObject(&bmpRacket);
pDC->BitBlt(point.x-80,point.y-
30,point.x+79,point.y+29,&mDC,0,0,SRCCOPY);
mDC.SelectObject(bmpOld);
currentMousePoint.x=point.x;
currentMousePoint.y=point.y;
oldMousePoint.x=point.x;
oldMousePoint.y=point.y;
}

CDialog::OnMouseMove(nFlags, point);
}


引用未解決
トピックタグ
nasu
 nasu
(@nasu)
ゲスト
結合: 22年前
投稿: 4
 

「ちらつき」で過去ログ検索


返信引用
Beginner
 Beginner
(@Beginner)
ゲスト
結合: 23年前
投稿: 63
Topic starter  

nasu様、

ご指摘ありがとうございました。
この検索は既に行い、試しましたがDelphiで書いたプログラムのようには
上手にちらつき防止は出来ません。
その故に恥を忍んでの質問です。
何かヒントでもご教授下さい。


返信引用
Beginner
 Beginner
(@Beginner)
ゲスト
結合: 23年前
投稿: 63
Topic starter  

nasu様、

ご指摘ありがとうございました。
この検索は既に行い、試しましたがDelphiで書いたプログラムのようには
上手にちらつき防止は出来ません。
その故に恥を忍んでの質問です。
何かヒントでもご教授下さい。


返信引用
nasu
 nasu
(@nasu)
ゲスト
結合: 22年前
投稿: 4
 

>この検索は既に行い、試しましたが
具体的にどう試したのですか?
そのコードをここに載せてみては?

>上手にちらつき防止は出来ません。
上手にちらつき防止が出来ないとは、具体的にどうなったのですか?

出来ない出来ないと言ってるだけでは、こっちは何もわかりませんよ。


返信引用
ナオーバ
 ナオーバ
(@ナオーバ)
ゲスト
結合: 23年前
投稿: 187
 

違っていたらすみません
CBlockHitCPPDlgからしてダイアログベースとして進めます

まずBOOL型のメンバ変数 m_bDrawを追加
コンストラクタでFALSEに設定しておいて
OnMouseMoveの if (point.y>400)をif( m_bDraw )に変更してOnPaintのelse内に移して

OnMouseMoveを↓のように変更します
void CBlockHitCPPDlg::OnMouseMove(UINT nFlags, CPoint point)
{
if(point.y>400) m_bDraw = TRUE;
else m_bDraw = FALSE;

CDialog::OnMouseMove(nFlags, point);
}

WM_ERASEBKGNDのハンドラを追加して以下のようにする
BOOL CBlockHitCPPDlg::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}

WM_ERASEBKGNDのハンドラ追加方法
ウィザードバーの一番右の▼を押してWindowsメッセージハンドラの追加を選択
ここで左側にWM_ERASEBKGNDがあれば選択して追加と編集ボタンを押す
無い場合は右下のクラスで使用可能なメッセージ用フィルタからウィンドウを選択
これで表示されるので選択して追加と編集ボタンを押す

で解決するハズです
チラツキ防止はOnEraseBkgndのオーバーライドで解決する場合が多いですよ。
っていうか私はこれしか知りません
詳しい事はこれらの内容からキーワードを探して調べてください


返信引用
Beginner
 Beginner
(@Beginner)
ゲスト
結合: 23年前
投稿: 63
Topic starter  

nasu様、

申し訳ありません。小生がトライしたのは、compatible memery DCを作成して、
そこに書き込んでからBitBltする方法、背景の書き直しをFillRectで
小範囲のみにする方法、背景の書き直しについて背景と同等のbmpを作成して
BitBltする方法でしたが、画面のちらつきは抑制できませんでした。
今、出先なのでコードをお送りできません。
申し訳ありません。

ナオーバ様、

ご親切にありがとうございます。
今、遠くに出先なのでトライできませんので、帰ってから早速トライしてみます。
また、ご指導の如く、キーワードで検索してみます。

結果できましたら、うまくいくいかないに関わらずご報告いたします。


返信引用
Beginner
 Beginner
(@Beginner)
ゲスト
結合: 22年前
投稿: 5
 

nasu様、

まず、以下のように前の位置のラケット消去と現位置のラケット書き込みを一旦、mDC2に
行い、合成し、それをmDCに転送したのち一挙に画面DCに転送を試みましたが、マウスの移動に
伴いちらつくままでした。

void CBlockHitCPPDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォル
トの処理を呼び出してください
if (point.y>400)
{
CDC* pDC=GetDC();
CDC mDC, mDC2;
CBitmap bmpRacket, *bmpOld;
CBitmap bmpRacket1, *bmpOld1;
bmpRacket.LoadBitmap(IDB_RACKET);
bmpRacket1.LoadBitmap(IDB_RACKET1);
//ラケットの前の位置を消去する

// pDC->FillSolidRect(oldMousePoint.x-80, oldMousePoint.y-30,
oldMousePoint.x+79, oldMousePoint.y+29,RGB(0,0,0));

mDC.CreateCompatibleDC(pDC);
mDC2.CreateCompatibleDC(pDC);//ラケット消去とあらたな書き込みの
合成用
bmpOld1=mDC2.SelectObject(&bmpRacket1);
pDC->BitBlt(oldMousePoint.x-80, oldMousePoint.y-30,
oldMousePoint.x+79, oldMousePoint.y+29,&mDC2,0,0,SRCCOPY);

bmpOld=mDC2.SelectObject(&bmpRacket);
pDC->BitBlt(point.x-80,point.y-
30,point.x+79,point.y+29,&mDC2,0,0,SRCCOPY);
mDC2.SelectObject(bmpOld);
pDC->BitBlt(0,0,1000,800,&mDC2,0,0,SRCCOPY);
pDC->BitBlt(0,0,1000,800,&mDC,0,0,SRCCOPY);
currentMousePoint.x=point.x;
currentMousePoint.y=point.y;
oldMousePoint.x=point.x;
oldMousePoint.y=point.y;
}

CDialog::OnMouseMove(nFlags, point);
}

ナオーバ様の方法も順次、試みます。
なお、小生は初心者氏とは別人です。


返信引用
Beginner
 Beginner
(@Beginner)
ゲスト
結合: 23年前
投稿: 63
Topic starter  

nasu様、

試してみました。具体的には以下のようです
OnPaintのelse以下に持ってきました。mousePointをメンバー変数のcurrentMousePointに
OnMouseMoveで代入して、それを用いています。
else
{
if (m_bDraw==TRUE)
{
CPoint point;
CDC* pDC=GetDC();
CDC mDC;
CBitmap bmpRacket, *bmpOld;
CBitmap bmpRacket1, *bmpOld1;
bmpRacket.LoadBitmap(IDB_RACKET);
bmpRacket1.LoadBitmap(IDB_RACKET1);
//ラケットの前の位置を消去する
point.x=currentMousePoint.x;
point.y=currentMousePoint.y;

mDC.CreateCompatibleDC(pDC);
bmpOld1=mDC.SelectObject(&bmpRacket1);
pDC->BitBlt(oldMousePoint.x-80, oldMousePoint.y-30,
oldMousePoint.x+79, oldMousePoint.y+29,&mDC,0,0,SRCCOPY);

bmpOld=mDC.SelectObject(&bmpRacket);
pDC->BitBlt(point.x-80,point.y-
30,point.x+79,point.y+29,&mDC,0,0,SRCCOPY);
mDC.SelectObject(bmpOld);
pDC->BitBlt(0,0,1000,800,&mDC,0,0,SRCCOPY);
// currentMousePoint.x=point.x;
// currentMousePoint.y=point.y;
oldMousePoint.x=point.x;
oldMousePoint.y=point.y;
}

CDialog::OnPaint();
}
}
そして、ハンドラを追加し、
BOOL CBlockHitCPPDlg::OnEraseBkgnd(CDC* pDC)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォル
トの処理を呼び出してください
return TRUE;
// return CDialog::OnEraseBkgnd(pDC);
}
としました。

また、OnMouseMoveについては
if (point.y>400)
m_bDraw = TRUE;
else
m_bDraw = FALSE;

CDialog::OnMouseMove(nFlags, point);
}
としました。
しかし、今度は真っ白なDialog boxが出来てしまい(多分全く書き込みがされていない)、勿論
ラケットも書かれません。色々と試してみます。


返信引用
Beginner
 Beginner
(@Beginner)
ゲスト
結合: 23年前
投稿: 63
Topic starter  

ナオーバ様、失礼しました。

先の状況報告は誤りでした。
OnMouseMoveに伴うチラツキをはっきりさせるために、OnTimerによるボールの動き部分を完全
にコメントアウトしていました。このコメントアウトを戻すと、ちゃんと画面が書かれ、またボ
ールも動きます。しかし、ボールの動きに伴い、画面がちらつきます。
しかし、今度はラケットが書かれませんでした。
自分で解決できるよう頑張ります。
きっとOnTimerで書きにいっているのもOnPaintに持って来れば良いのかも知れません。


返信引用
nasu
 nasu
(@nasu)
ゲスト
結合: 22年前
投稿: 4
 

>まず、以下のように前の位置のラケット消去と現位置のラケット書き込みを一旦、mDC2に
>行い、合成し、それをmDCに転送したのち一挙に画面DCに転送を試みましたが

どう見ても画面に直接BitBltしてるようにしか見えないんですけど・・・


返信引用
Beginner
 Beginner
(@Beginner)
ゲスト
結合: 23年前
投稿: 63
Topic starter  

nasu様、

ヒントありがとうございます。
とんでもない間違いをしているのかも知れません。
検討します。


返信引用
ナオーバ
 ナオーバ
(@ナオーバ)
ゲスト
結合: 23年前
投稿: 187
 

間違っていたらすみません。
まだまだ修行不足のVC暦1年の言うこととして聞いて下さい。

メモリDCで全て作成して画面に一気に出力したいのですよね?

pDC->BitBlt(転送先, 転送元DC, 転送元, コード);のとき
pDCに転送先DCが割り当てられます。
なので、BeginnerさんのソースではpDC->BitBltが3回あるので
1回の描画命令で3回画面に書くことになると思います。

それとチラツキと関係ないのですが
mDC.SelectObject(bmpOld);で元に戻されていませんよね?
mDC.SelectObject(bmpOld1);ではないでしょうか
最初に保存しといて、使いまわした後に元に戻すのが正解では?

OnTimerの部分も書いた方がレスがつきやすいかも。


返信引用
Beginner
 Beginner
(@Beginner)
ゲスト
結合: 23年前
投稿: 63
Topic starter  

ナオーバ様、

詳しくありがとうございます。
OnTimerの部分はこのように書きました。
ご指摘のようにpDCに対して何回もBitBltしています。
これを修正している間にコードがぐちゃぐちゃになってしまい、始めに立ち返ってやり直しま
す。すみません。
SelectObjectについてもぐちゃぐちゃになって混乱していました。

void CBlockHitCPPDlg::OnTimer(UINT nIDEvent)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォル
トの処理を呼び出してください

if (nIDEvent==1) {
CDC* pDC=GetDC();
CDC mDC;
CBitmap blockImg, *oldImg;
CBitmap ballImgOr, ballImgAnd, *oldImgOr, *oldImgAnd;
mDC.CreateCompatibleDC(pDC);
pDC->FillSolidRect(Ball.BallPosition.x-
15,Ball.BallPosition.y-15,
Ball.BallPosition.x+14,Ball.BallPosition.y+14,RGB
(0,0,0)); //前の位置のボールを消去

blockImg.LoadBitmap(IDB_BLOCK);
ballImgOr.LoadBitmap(IDB_BALLOR);
ballImgAnd.LoadBitmap(IDB_BALLAND);

oldImg=mDC.SelectObject(&blockImg);
for (int i=0; i<10; i++) {
for (int j=0; j<3; j++) {
int k=i + j*10;
if (Block[k].LiveOrDead==Living) {
pDC->BitBlt(Block
[k].Position.left, Block[k].Position.top,
Block[k].Position.right,
Block[k].Position.bottom,&mDC,0,0,SRCCOPY);
if (Block[k].Position.PtInRect
(Ball.BallPosition)) { //ボールがブロックにあたった
Block
[k].LiveOrDead=Dead; //ブロックを消す
MessageBeep
(MB_ICONASTERISK);
Ball.YSpeed=-Ball.YSpeed;
}
}
if (Block[k].LiveOrDead==Dead)
pDC->FillSolidRect(Block
[k].Position.left, Block[k].Position.top,
Block[k].Position.right,
Block[k].Position.bottom, RGB(0,0,0));
}
}

mDC.SelectObject(oldImg);

Ball.BallPosition.x=Ball.BallPosition.x+Ball.XSpeed;
Ball.BallPosition.y=Ball.BallPosition.y+Ball.YSpeed;
if (Ball.BallPosition.x>=965) Ball.XSpeed=-Ball.XSpeed; //壁の
判定
if (Ball.BallPosition.x<=5) Ball.XSpeed=-Ball.XSpeed;
if (Ball.BallPosition.y>=765) Ball.YSpeed=-Ball.YSpeed;
if (Ball.BallPosition.y<=5) Ball.YSpeed=-Ball.YSpeed;

CRect rc;
rc.SetRect(currentMousePoint.x-80,currentMousePoint.y-
30,currentMousePoint.x+79,currentMousePoint.y+29);
if (rc.PtInRect(Ball.BallPosition)) { //ボールがラケットにあた
った
Ball.YSpeed=-Ball.YSpeed;
MessageBeep(MB_OK);
}

oldImgAnd=mDC.SelectObject(&ballImgAnd); //ポールの描き込み
pDC->BitBlt(Ball.BallPosition.x-15, Ball.BallPosition.y-15,
Ball.BallPosition.x+14,
Ball.BallPosition.y+14,&mDC,0,0,SRCAND);
mDC.SelectObject(oldImgAnd);
oldImgOr=mDC.SelectObject(&ballImgOr);
pDC->BitBlt(Ball.BallPosition.x-15, Ball.BallPosition.y-15,
Ball.BallPosition.x+14,
Ball.BallPosition.y+14,&mDC,0,0,SRCCOPY);
mDC.SelectObject(oldImgOr);
}

CDialog::OnTimer(nIDEvent);
}


返信引用
Beginner
 Beginner
(@Beginner)
ゲスト
結合: 23年前
投稿: 63
Topic starter  

コードがぐちゃぐちゃになってしまいましたので、物事をはっきりさせるために、新たにOff
Screenを用いた簡単な動画を作成しました。

void COffScreenTestDlg::OnTimer(UINT nIDEvent)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォル
トの処理を呼び出してください
if (nIDEvent==1) {
CDC *pDC = GetDC();
CDC mDC, oDC;
CBitmap bmpBlock, *bmpOld;
mDC.CreateCompatibleDC(pDC);
oDC.CreateCompatibleDC(pDC);
bmpBlock.LoadBitmap(Racket);
bmpOld=mDC.SelectObject(&bmpBlock);
oDC.BitBlt(point.x++,point.y++,(point.x++)+32,(point.y++)
+32,&mDC,0,0,SRCCOPY);
          mDC.SelectObject(&bmpOld);
pDC->BitBlt(0,0,1000,800,&oDC,0,0,SRCCOPY);

if (point.x>950) point.x=0;
if (point.y>750) point.y=0;
}

CDialog::OnTimer(nIDEvent);
}
しかしながら、画面に動画が現れません。一旦、BitmapをmDCに選択し、それをoDCに転送して
から、pDCに転送するというものです。何が悪いでしょうか。ご教授下さい。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました