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

Ownerdraw listctrl with transparent background and customized items image on WinCE

0.00/5 (No votes)
5 Jan 2012 2  
Ownerdraw listctrl with transparent background and custermized items image on WinCE.

 Introduction 

  Download ownerDrawList.zip - 4.76 MB  

 Owner-draw listctrl with transparent background and customized items(with checkbox) image on wince

ownerdraw_listctrl.PNG 

Background   

I am developing a media player which should be running on windows embedded compact 7 system with customized hardware. Before this project, I have 0 experience of MFC and last time I did a windows based development was 10 years ago using C++builder. I am now actually a linux developer. Luckily with help of google/codeproject, I finished all things in 2 weeks. The purpose of this article is to help those developers which may have similar situation.

At first since I did not get hardware on hand, I have done all the development on windows desktop environment( windows 7). When I am trying to port code to wince platform, I found that  wince did not support owner-draw listbox which I used to display playlist. Then I turn to use listctrl. I spent a day to convert my code from listbox to listctrl. Thanks again for codeproject.

Using the code

I create a new class MyListCtrl inherited from MFC ListCtrl and adding below features

  • ability to set bitmap image for item icon
  • ability to set bitmap image for item highlight
  • ability to set bitmap image for item checkbox
  • ability to be transparent to parent window
  • ability to set item height

 Below are corresponding interfaces for setting the image from resource ID

    //set highlight image     
    void SetItemHighlightImg(UINT id); 
    // set item icon
    void SetItemIcon(UINT id); 
    // set image of "Checkbox" in unchecked status
    void SetItemCheckedImg(UINT id);
    // set image of "Checkbox" in checked status
    void SetItemUnCheckedImg(UINT id); 
    // set background
    void SetBk(CDC *pDC); 

The core function for a owner-draw list ctrl is DrawItem

void MyListCtrl::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
{
    ASSERT(::IsWindow(m_hWnd));
    ASSERT(lpDrawItemStruct != 0);
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    CRect rcItem(lpDrawItemStruct->rcItem);
    int nItem = lpDrawItemStruct->itemID;

    LV_ITEM lvi;
    lvi.mask = LVIF_STATE;
    lvi.iItem = nItem;
    lvi.iSubItem = 0;
    lvi.stateMask = 0xFFFF;     // get all state flags
    GetItem(&lvi);

    BOOL bHighlight = lvi.state & LVIS_FOCUSED;

    CRect rcBounds;
    GetItemRect(nItem, rcBounds, LVIR_BOUNDS);
    CString sLabel = GetItemText(nItem, 0);

    PaintBk(pDC, rcItem);

    HBITMAP		hbmOldBmp	= NULL;

    CDC bitmapDC;
    bitmapDC.CreateCompatibleDC(pDC);

    
    if (bHighlight)
    {
        hbmOldBmp = (HBITMAP)bitmapDC.SelectObject(m_SelImg);
        pDC->BitBlt(rcItem.left, rcItem.top, rcItem.Width(), rcItem.Height(), &bitmapDC,0,0,SRCCOPY);
        bitmapDC.SelectObject(hbmOldBmp);
    }

    ResConfigRec iRec = SkinConfigMgr::GetResConfig(IDB_IMG_ITEM_ICON);
    hbmOldBmp = (HBITMAP)bitmapDC.SelectObject(m_ItemIcon);
    pDC->BitBlt(rcItem.left + iRec.resX, rcItem.top + iRec.resY, iRec.resW, iRec.resH, &bitmapDC,0,0,SRCCOPY);
    bitmapDC.SelectObject(hbmOldBmp);

    // NOTE: Please replace below code block with your own logic
    // In my implementation, I used std::vector<int> to store checkbox status of each items
    // std::vector<int>* m_pStatusMap
#if 0
    iRec = SkinConfigMgr::GetResConfig(IDB_IMG_ITEM_UC);
    int checked = m_pStatusMap->at(nItem);
    if ((rcItem.left + iRec.resX < bMouseDownPos.x && bMouseDownPos.x < rcItem.left + iRec.resX +iRec.resW)
        &&(rcItem.top + iRec.resY < bMouseDownPos.y && bMouseDownPos.y < rcItem.top + iRec.resY +iRec.resH))
    {
        std::vector<int>::iterator iter = m_pStatusMap->begin()+nItem;
        if (checked == 1)
        {
            *iter = 0;
        }
        else
        {
            *iter = 1;
        }
        checked = *iter;
        bMouseDownPos.x = 0;
        bMouseDownPos.y = 0;
    }
#endif

    CFont font;
    font.CreatePointFont(200, _T("Times New Roman")); 
    pDC->SelectObject(&font);
    pDC->SetTextColor(RGB(255,255,255));
    pDC->DrawText(sLabel,rcItem, DT_CENTER);

    if (checked == 1)
    {
        hbmOldBmp = (HBITMAP)bitmapDC.SelectObject(m_CbChecked);
        pDC->BitBlt(rcItem.left + iRec.resX, rcItem.top + iRec.resY, iRec.resW, iRec.resH, &bitmapDC,0,0,SRCCOPY);
        bitmapDC.SelectObject(hbmOldBmp);
    }
    else
    {
        hbmOldBmp = (HBITMAP)bitmapDC.SelectObject(m_CbUnChecked);
        pDC->BitBlt(rcItem.left + iRec.resX, rcItem.top + iRec.resY, iRec.resW, iRec.resH, &bitmapDC,0,0,SRCCOPY);
        bitmapDC.SelectObject(hbmOldBmp);
    }

}

To change the status of checkbox, we need to handle message ON_WM_LBUTTONDOWN  and record mouse down position

CPoint bMouseDownPos;
void MyListCtrl::OnLButtonDown( UINT nFlags, CPoint point )
{
    bMouseDownPos = point;
    Default();
    int iPos = GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);
    CRect rcItem;
    GetItemRect(iPos, &rcItem, LVIR_BOUNDS);
    // NOTE: replace this code with your own logic
    //ResConfigRec iRec = SkinConfigMgr::GetResConfig(IDB_IMG_ITEM_UC);
    //if ((rcItem.left + iRec.resX < bMouseDownPos.x && bMouseDownPos.x < rcItem.left + iRec.resX +iRec.resW)
     //   &&(rcItem.top + iRec.resY < bMouseDownPos.y && bMouseDownPos.y < rcItem.top + iRec.resY +iRec.resH))
    //{
    //    InvalidateRect(&rcItem);
    //}
}

Points of Interest  

   The usage of MeasureItem to set item height did not work for listctrl. A simple way to set item height is to use a imagelist.

    m_imageList.Create(24, 58, ILC_COLOR4,10,10 );   
    myList.SetImageList(   &m_imageList,   LVSIL_SMALL   );

History 

Keep a running update of any changes or improvements you've made here.  

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