Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

FLICKER-free

0.00/5 (No votes)
27 Apr 2003 1  
how to implement double buffer in the list cnntrol to avoid flipping

Introduction

This is the main window of the cabnet project.

As you see - the list control contains the driver's numbers identification - placed time sortly. Cabnet - usging the list control without
flickering

While usually the MFC technique to draw the list controls items is sufficient, i had confronted a crises with my last project. the drawing operations inside the internal OnPaint function was truely heavy, And the view was flickly disaster.

Conclusion : don't take the flicking - flippancy !!! To avoid flicking in the list control you have to create your own extention to the original CListCtrl class and to implement the following functions.

class CListCtrlEx : public CListCtrl 
{
    protected:
    void DrawItem(LPDRAWITEMSTRUCT);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg void OnPaint();
    public:  
    void SetCustomFont(int nSize,LPCSTR szName)
    protected :

    TEXTMETRIC m_fnt_tm;
    CFont m_fntCustom;
    ...
    ...
    
    DECLARE_MESSAGE_MAP()
}

You could choose a custom font :

void CListCtrlEx::SetCustomFont(int nSize,LPCSTR szName)
{

    if (m_fntCustom,GetSafeHandle())
        m_fntCustom.DestroyFont();
    m_fntCustom.CreateFont(nSize, 0, 0, 0, 400, FALSE, FALSE, 0,
                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
                    CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
                    DEFAULT_PITCH | FF_SWISS,szName);
    SetFontHeight()

}
void CListCtrlEx::SetFontHeight()
 {
     CClientDC dc(this);
     // select font or stay with the default font
     CFont *pFontOld = NULL; 
     if (m_fntCustom.GetSafeHandle())
         pFontOld = dc.SelectObject(&m_fntCustom);

     TEXTMETRIC tm;
     ::GetTextMetrics(dc.m_hDC,&tm);     
     m_fnt_tm = tm;
     // drop font
     if (pFontOld) dc.SelectObject(pFontOld);
 }
BOOL CListCtrlEx::OnEraseBkgnd(CDC* pDC) 
{
    return 1;
    //return CListCtrl::OnEraseBkgnd(pDC); // this is the criminal 
                                               // who make the most flicking problems...

}
void CListCtrlEx::OnPaint() 
{
    CPaintDC dc(this); // device context for painting
    int nVertPos;
    CDC dcm;    
    CRect rc;
    GetClientRect(rc);
    dcm.CreateCompatibleDC(&dc);
    CBitmap bmt;
    bmt.CreateCompatibleBitmap(&dc,rc.Width(),rc.Height());
    CBitmap *pBitmapOld = dcm.SelectObject(&bmt);
    
    dcm.Rectangle(rc);// make the work of the OnEraseBkgnd function
        
    DRAWITEMSTRUCT dd;
    dd.hwndItem = m_hWnd;
    dd.hDC = dc.m_hDC;
        dc.SetBkMode(TRANSPARENT); 
    // select objects as && if you like 
       
        nVertPos = GetScrollPos(SB_VERT);
      if (nVertPos!=0) {
      nVertPos = nVertPos/m_fnt_tm.tmHeight;
}


    for (int v=0; v<rc.Height()/m_fnt_tm.tmHeight; v++) {
     
        dd.itemID = v+nVertPos;    
        DrawItem(&dd);


    }
    BitBlt(dc.m_hDC,0,0,rc.Width(),rc.Height(),dcm.m_hDC,0,0,SRCCOPY);

    dcm.SelectObject(pBitmapOld);
    // drop other objects from the dc context memory - if there are.


}
void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT ld) 
{
         CHeaderCtrl* pHeader = GetHeaderCtrl( );
         int nCols = pHeader->GetItemCount( );
         CRect rf;
         int nVertPos = GetScrollPos(SB_VERT);
         
         for (int nIndex=0; nIndex<nCols; nIndex++) 
         {
              GetSubItemRect( ld->itemID, nIndex,LVIR_BOUNDS , rf);
              rf.top -= nVertPos;
              rf.bottom = rf.top + m_fnt_tm.tmHeight;
                        
             // draw what ever you like on the rf rectangle...
         }
}
Finally, you have to create the list control with the LVS_OWNERDRAWFIXED style.

note : if you decide to choose custom font you have also to implement the GetSubItemRect function because the re-paint rectangle should be in regard to the custom font size.

BOOL CListCtrlEx::GetSubItemRect(int iItem, int iSubItem, int nArea, CRect &ref)
{
        BOOL bRet = CListCtrl::GetSubItemRect( iItem, iSubItem, nArea, ref );
        if (!m_fntCustom.GetSafeHandle()) return bRet;
        ref.top = (iItem*m_fnt_tm.tmHeight);
        ref.bottom=ref.top+m_fnt_tm.tmHeight;
        return bRet;
}
p.s : If the list control has the WS_HSCROLL style - you have to adjust the drawing the same way we used for the WS_VSCROLL case - by using the GetScrollPos() function with the value SB_HORZ for its argument.

tip

bitmap store for speedness and memory saving

If you have multiple windows to draw by yourself - consider to use big CBitmap variable stored in stack or in the heap for the life of the app, and take it as your memory storeroom for all your painting.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here