MFCデュアルバッファによる画像フリッカの解決


ネット上で見つけた二重バッファの文章を転載して、とても使いやすいです.
表示パターンが点滅を回避する方法、表示効率を向上させる方法は多くの質問です.また,MFCの図形描画関数は効率が低く,常に他の解決策を求めたいと考えている人が多い.MFCの描画効率は確かに高くないが悪くないし、その描画関数の使用は非常に簡単で、使用方法が適切であれば、いくつかのテクニックを加えて、MFCで効率の高い描画プログラムを得ることができます.私は長い間(ほほほもちろん2年以上しかありません)MFCの絵を使った経験について私のいくつかの観点を話したいと思います.
1、表示されている図形がなぜ点滅するのか.
私たちの描画プロセスの多くはOnDrawまたはOnPaint関数にあり、OnDrawは画面表示時にOnPaintによって呼び出されます.ウィンドウが何らかの理由で再描画する必要がある場合、常に背景色で表示領域をクリアしてからOnPaintを呼び出すが、背景色は図面の内容と大きく異なることが多く、短時間で背景色と表示図形が交互に現れ、表示ウィンドウが点滅しているように見える.バックグラウンドブラシをNULLに設定すると、どのようにグラフィックを再描画しても点滅しません.もちろん、再描画時に背景色がなく、元の描画した図形を消去し、新しい図形を重ねたため、ウィンドウの表示が混乱します.点滅は、描画速度が遅すぎるか、表示されている図形が複雑すぎるためだと言う人もいますが、実はそうではありません.描画の表示速度が点滅に与える影響は根本的ではありません.例えば、OnDraw(CDC*pDC)では、pDC->MoveTo(0,0);pDC->LineTo(100,100);
この描画プロセスは非常に簡単で、非常に速いのではないでしょうか.しかし、ウィンドウを引っ張ると点滅が見えます.実は理屈から言えば、絵を描く過程が複雑であればあるほど遅く点滅するのは少ないはずです.絵を描く時間と背景でスクリーンを消す時間の割合が大人ほど点滅に対する感覚が明らかではないからです.例えば、スクリーン時間が1 sの描画時間も1 sであることが明らかになり、10 s内の連続再描画で5回点滅する.スクリーン時間が1 sで変化せず、描画時間が9 sであることが分かれば、10 s内の連続再描画は1回しか点滅しません.これは、OnDraw(CDC*pDC)においても、for(int i=0;i<100000;i+){pDC->MoveTo(0,i);pDC->LineTo(1000,i);}ほほほ、プログラムは少し変態ですが、問題を説明することができます.
ここまで言うと、簡単な図形が複雑な図形ほどキラキラしていないのはなぜですか.これは,複雑な図形が占める面積が大きく,再描画時のギャップが大きいため,強く点滅するように感じられるが,点滅周波数は低いためである.では、なぜアニメーションの再描画頻度が高く、点滅しないように見えますか?ここで、私は再び強調します.点滅は何ですか.点滅はギャップで、ギャップが大きいほど、点滅が激しくなります.アニメーションの連続する2つのフレームの差が小さいため、点滅しないように見えます.信じなければ、アニメーションのフレームごとに純白のフレームを追加することができます.フラッシュしないのはおかしいですね.
2、点滅を避ける方法
グラフィックが点滅する原因を知ってから、対症的に薬を処方すればやりやすい.まず、もちろんMFCが提供する背景描画プロセスを削除します.実現する方法は多く、*ウィンドウ形成時にウィンドウの登録クラスのバックグラウンドにNULLをブラシすることもできるし、形成後にバックグラウンドstatic CBrush brush(RGB(255,0,0))を修正することもできる.   SetClassLong(this->m_hWnd,GCL_HBRBACKGROUND,(LONG)(HBRUSH)brush);* 簡単にまたOnEraseBkgnd(CDC*pDC)をリロードして直接TRUEに戻ることもできます
このように背景がなくなって、結果的にグラフィック表示は確かに点滅しなくなったが、表示も前述のように、めちゃくちゃになった.どうしよう?これでデュアルキャッシュの方法が使用されます.デュアルバッファは、画面にグラフィックが表示されているほか、メモリにグラフィックが描かれていることもあります.表示するグラフィックをメモリに描画してから、メモリ内のグラフィックを一度に1つのポイントで画面に上書きすることができます(このプロセスは非常に速く、非常に規則的なメモリコピーであるため).このようにメモリに絵を描くときは、どんなギャップの大きい背景色でも点滅しません.見えないからです.画面に貼り付けると、メモリ内の最終的なグラフィックと画面表示グラフィックの差が小さいため(動きがなければもちろん差はありません)、点滅しないように見えます.
3、デュアルバッファの実現方法
まず実装されたプログラムを示し、次に説明する.同様にOnDraw(CDC*pDC)において:
CDC MemDC; //            
CBitmap MemBitmap;//        

//                  
MemDC.CreateCompatibleDC(NULL);
//       ,        ^_^
//                ,        ,        
MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);

//             
//                    ,        
CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);

//            ,            
//             
MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));

//  
MemDC.MoveTo(……);
MemDC.LineTo(……);

//                
pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY);

//        
MemBitmap.DeleteObject();
MemDC.DeleteDC();

上の注釈は詳しいはずですが、くだらないことはあまり言わないでください.
4、図面の効率を高める方法
私が主にやっているのは電力システムのネットワークグラフィックのCADソフトウェアで、1つのウィンドウの中で往々にして何千もの電力素子を表示しなければならないが、各素子は点、線、円などの基本的なグラフィックから構成されている.本当に1回の再描画プロセスでこんなに多くの要素を再描画するなら、このプロセスは非常に長いことがわかります.グラフィックのブラウズ機能が加わると、マウスでグラフィックをドラッグしてスクロールする際に大量の再描画が必要になり、ユーザーが耐えられないほど速度が遅くなります.どうしよう?MFCの描画過程を再検討するしかない.
実際、OnDraw(CDC*pDC)で描かれた図はすべて表示されているわけではありません.たとえば、OnDrawで2つの長方形を描き、1回の再描画では2つの長方形の描画関数が実行されますが、MFC本体が再描画の効率を高めるためにトリミング領域を設定している可能性が高いため、1つだけ表示されている可能性があります.トリミング領域の役割は、この領域内の描画プロセスのみが本当に有効であり、領域外では無効であり、領域外で描画関数が実行されても表示されません.多くの場合、ウィンドウ再描画の発生の多くは、ウィンドウ部分が遮蔽されたり、ウィンドウがスクロールされたりしているため、変更された領域はグラフィック全体ではなく、ほんの一部であり、この部分を変更する必要があるのはpDCのトリミング領域である.描画プロセスの計算よりも表示(メモリまたはディスプレイメモリに表示)に時間がかかるため、トリミング領域があれば表示すべき部分だけが表示され、表示効率が大幅に向上します.しかし、このトリミング領域はMFCで設定されており、表示効率が向上していますが、複雑な図形の描画を行う際にどのように効率を向上させるのでしょうか.それは裁断区の外にある描画過程を取り除くしかない.まずpDC->GetClipBox()で裁断領域を取得し、図面を描くときにあなたの図形がこの領域内にあるかどうかを判断し、そこにあれば描き、いなければ描きません.
描画プロセスが複雑でない場合は、描画効率が向上しない可能性があります.