Click here to Skip to main content
Click here to Skip to main content

Ownerdraw listctrl with transparent background and customized items image on WinCE

By , 5 Jan 2012
 

 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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Pansion_chen
Software Developer (Senior)
China China
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionCompraron el códigomemberMember 871442110 Aug '12 - 4:41 
Aca es así, cuando hay un código muy bueno lo quitan y lo venden !!
QuestionThe bitmaps are missing?...membercyfage5 Aug '12 - 15:36 
1>.\ownerDrawList.rc(156) : error RC2135 : file not found: E:\DSPlayer_MFC\DSPlayer_MFC\res\kuang_n.bmp
1>.\ownerDrawList.rc(157) : error RC2135 : file not found: E:\DSPlayer_MFC\DSPlayer_MFC\res\xuanzhong_n.bmp
1>.\ownerDrawList.rc(158) : error RC2135 : file not found: E:\DSPlayer_MFC\DSPlayer_MFC\res\dv_icon.bmp
1>.\ownerDrawList.rc(159) : error RC2135 : file not found: E:\DSPlayer_MFC\DSPlayer_MFC\res\gou_icon_n.bmp
1>.\ownerDrawList.rc(160) : error RC2135 : file not found: E:\DSPlayer_MFC\DSPlayer_MFC\res\dv-bj.bmp
Questionbitmaps missingmemberRoger656 Jan '12 - 22:38 
You have some private bitmaps on your E: drive that you didn't include with the project.
Old dog learning new tricks!

QuestionNo project, no full source code, just waste the readers' time.membertohjs14 Dec '11 - 11:43 
No project, no full source code, just waste the readers' time.
AnswerRe: No project, no full source code, just waste the readers' time.memberPansion_chen5 Jan '12 - 17:04 
Oops, I forget to add link in my article.
updated.
Pansion not Passion!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 5 Jan 2012
Article Copyright 2011 by Pansion_chen
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid