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.
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);
CFont *pFontOld = NULL;
if (m_fntCustom.GetSafeHandle())
pFontOld = dc.SelectObject(&m_fntCustom);
TEXTMETRIC tm;
::GetTextMetrics(dc.m_hDC,&tm);
m_fnt_tm = tm;
if (pFontOld) dc.SelectObject(pFontOld);
}
BOOL CListCtrlEx::OnEraseBkgnd(CDC* pDC)
{
return 1;
}
void CListCtrlEx::OnPaint()
{
CPaintDC dc(this); 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);
DRAWITEMSTRUCT dd;
dd.hwndItem = m_hWnd;
dd.hDC = dc.m_hDC;
dc.SetBkMode(TRANSPARENT);
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);
}
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;
}
}
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.