1. 程式人生 > >重繪閃爍問題總結

重繪閃爍問題總結

重繪閃爍,通常,首先需要懷疑的是WM_ERASEBKGND訊息。當一個視窗的背景需要被擦除時,這個訊息會被髮送。這是因為視窗的繪畫通常經歷了兩個過程 
WM_ERASEBKGND: 清除背景 
WM_PAINT: 在上面繪製內容 

這兩個過程讓窗體在繪製內容時變得很簡單,即:每次當收到WM_PAINT訊息時,你知道已經有了一個新畫布等待去繪製。然而,畫視窗兩次(一次是通過WM_ERASEBKGND畫背景,另外一次是WM_PAINT)將會導致窗口出現比較糟糕的閃爍現象。只要看看標準的編輯框-開啟Windows的寫字板並改變視窗大小,就可以看到那種閃爍的效果。 

那麼,如何避免視窗背景的重刷呢?有如下兩種方法: 
1、

設定視窗背景刷子為NULL(當註冊Windows類時,設定WNDCLASS結構中的hbrBackground成員為零) 
2、在WM_ERASEBKGND訊息處理時 返回非零值 
以上任何一種方法都可以阻止WM_ERASEBKGND 訊息去清除視窗。其中,第二個方案的通常可以以如下程式碼實現: 
case WM_ERASEBKGND:
return 1; 

3、當你標記視窗內容無效並試圖更新時,還有如下辦法可以防止WM_ERASEBKGND訊息:InvalidateRect函式的最後一個引數可以指明在下一次視窗重畫時,是否視窗的部分背景會被重刷。將該引數置為False可以防止當視窗需要重畫時系統發出WM_ERASEBKGND訊息。
 
InvalidateRect(hwnd, &rect, FALSE); 

4、剪下子窗體屬性中的Clip children  Clip Sibling 兄弟姐妹視窗
有時,閃爍的原因是因為當重畫時,父窗體沒有剪下其子窗體區域。這樣的結果導致,整個父視窗內容被重畫,而子窗體又被顯示在了上面(造成閃爍)。這個可以通過在父窗體上設定WS_CLIPCHILDREN 來解決。當這個標誌被設定時,被子窗體佔據的任何區域將會被排除在更新區域外。因此,即使你嘗試在子窗體所在的位置上繪製(父視窗的內容),BeginPaint中的剪下區域也會阻止其繪製效果。 

5、雙緩衝

CRectrt;     GetClientRect
(rt);
    CDC *pDC=GetDC();//最好用CPaintDC,CPaintDC只能在OnPaint函式有效     CDC MemDC     CBitmap MemBitmap;     MemDC.CreateCompatibleDC(pDC);     if (MemDC)     {         MemBitmap.CreateCompatibleBitmap(pDC,rt.right,rt.bottom);         CBitmap *pOldBit =MemDC.SelectObject(&MemBitmap);         MemDC.FillSolidRect(rt.left,rt.top,rt.right,rt.bottomRGB(0,0,0));         RealDraw(&MemDC);             pDC->BitBlt(rt.left,rt.top,rt.right,rt.bottom,&MemDC,rt.left,rt.top,SRCCOPY);         MemDC.SelectObject(pOldBit);         MemBitmap.DeleteObject();         MemDC.DeleteDC();     }     ReleaseDC(pDC);    

6、不該畫的時候一定不要畫