OnEraseBkgnd,OnPaintと画面再描画(呼び出し実装関係をよく説明)


問題の背景:
フォームが再描画されると、オーバー周波数のリフレッシュによって点滅する現象が発生します.フォームはリフレッシュ時に、元の画像を消去するプロセスOnEraseBkgndが必要です.これは、背景色を利用してフォームの描画領域を埋め、新しい描画コードを呼び出して再描画することで、画像の色のギャップをもたらします.WM_PAINTの応答が頻繁な場合、このギャップもますます顕著になります.
描画プロセス:
ウィンドウ全体を再描画する必要がある場合、システムは順次WM_を送信する.NCPAINT、WM_ERASEBKGND、WM_PAINTの3つの独立したメッセージ、すなわちまずフレーム部分を描画し、次にクライアント領域の背景を描画し、最後にクライアント領域を描画し、必要に応じてメッセージ応答を1つだけ生成することもできます.
Windowsコンポーネントのいずれかの図面は、OnPaint、OnEraseBkgndに配置されています.設定上、OnEraseBkgndは下図を描くためのものであり、OnPaintはメインオブジェクトを描くためのものである.例えば、1つのボタンが灰色で、上に文字がある場合、OnEraseBkgndが行うことはボタンを灰色に描くことであり、OnPaint()が行うことは文字を描くことである.
発生原因:
OnEraseBkGndでは、元のデフォルトのOnEraseBkGndを呼び出さずにバックグラウンドを再描画するだけでは点滅しません.
一方、OnPaintでは、OnEraseBkGndが暗黙的に呼び出されているため、OnEraseBkGnd関数が処理されていなければ、デフォルトのバックグラウンドブラシに関連する.デフォルトのOnEraseBkGnd操作では、ウィンドウのデフォルトのバックグラウンドブラシを使用してバックグラウンドをリフレッシュし(一般的には白ブラシ)、その後、自分でバックグラウンドを再描画してスクリーンをフラッシュします.もう一つの問題はOnEraseBkGndが毎回呼び出されるわけではないということです.Invalidateが呼び出されたときのパラメータがTRUEの場合、OnPaintにBeginPaintが暗黙的に含まれるときにWM_が生成されるERASEBKGNDメッセージは、パラメータがFALSEの場合、バックグラウンドは再ブラシされません. 
解決方法:
1.OnEraseBkGndで実装し、ベースクラスのOnEraseBkGnd関数を呼び出さない.
2.OnPaintで実装し、OnEraseBkGndを再ロードし、直接返します.
3.OnPaintで実現し、ウィンドウの作成時にバックグラウンドブラシを空に設定する(前の画像を消去できない).
4.OnPaintで実現しますが、リフレッシュを要求する場合はInvalidate(FALSE)という関数を使います(この場合、ウィンドウオーバーライドなどによるリフレッシュはやはりフラッシュするので、徹底した解決策ではありません).
構想解決まとめ:
OnPaintとOnEraseBkgndの比較:
1、OnEraseBkgndの要求は高速で、あまり時間をかけないほうがいいです.Windowsコンポーネントに小さな変更があるたびにOnEraseBkgndを使用します.
2、OnPaintは、プログラムに空きがある場合のみ呼び出されます.
3、OnEraseBkgndはOnPaintより前に呼び出されます.
OnPaintの前にOnEraseBkgndを何度も呼び出すことがあるので、比較的良い方法はOnPaintの方法がOnEraseBkgndによって実現されることです.
WM_PAINTメッセージ応答の頻度が高すぎて、最小化が最大化され、フォームの移動、オーバーライドなどが再描画され、パフォーマンスが消費されます.
したがって、デュアルキャッシュを使用すると、表示するグラフィックをメモリに描画してから、メモリのグラフィックを一度に画面に1点ずつ上書きできます.
以上より,OnEraseBkgndをリロードし,デュアルキャッシュにより画面フリッカの問題を解決した.
BOOL CSDRClientDlg::OnEraseBkgnd(CDC* pDC) 
{
// TODO: Add your message handler code here and/or call default
CRect rcClient;
GetClientRect(&rcClient);
BITMAP bmpBKG;
m_cBKGndBmp.GetBitmap(&bmpBKG);
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap *pOldBmp=memDC.SelectObject(&m_cBKGndBmp);
pDC->StretchBlt(0,0,rcClient.Width(),rcClient.Height(),&memDC,0,0,
                        bmpBKG.bmWidth,bmpBKG.bmHeight,SRCCOPY);
memDC.SelectObject(pOldBmp);
memDC.DeleteDC();
return TRUE;
        //return CDialog::OnEraseBkgnd(pDC);
 }