65.9K
CodeProject 正在变化。 阅读更多。
Home

WinCE 上带有透明背景和自定义项目图像的自绘列表控件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (9投票s)

2011 年 12 月 7 日

CPOL

2分钟阅读

viewsIcon

44420

downloadIcon

8869

WinCE 上带有透明背景和自定义项目图像的 Ownerdraw listctrl。

 简介 

  下载 ownerDrawList.zip - 4.76 MB 

 WinCE 上带有透明背景和自定义项目(带有复选框)图像的 Owner-draw listctrl

ownerdraw_listctrl.PNG 

背景   

我正在开发一个媒体播放器,该播放器应在带有自定义硬件的 Windows Embedded Compact 7 系统上运行。 在这个项目之前,我没有 MFC 的经验,而且上次进行基于 Windows 的开发是在 10 年前使用 C++Builder。 我现在实际上是一名 Linux 开发者。 幸运的是,在 Google/codeproject 的帮助下,我花了 2 周时间完成了所有事情。 本文的目的是帮助那些可能遇到类似情况的开发者。

首先,由于我没有手头硬件,我已在 Windows 桌面环境(Windows 7)上完成了所有开发。 当我尝试将代码移植到 wince 平台时,我发现 wince 不支持我用来显示播放列表的 owner-draw listbox。 然后我转向使用 listctrl。 我花了一天的时间将我的代码从 listbox 转换为 listctrl。 再次感谢 codeproject。

使用代码

我创建了一个名为 MyListCtrl 的新类,它继承自 MFC ListCtrl,并添加了以下功能

  • 能够为项目图标设置位图图像
  • 能够为项目高亮显示设置位图图像
  • 能够为项目复选框设置位图图像
  • 能够对父窗口透明
  • 能够设置项目高度

 以下是从资源 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); 

owner-draw list ctrl 的核心函数是 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);
    }

}

要更改复选框的状态,我们需要处理消息 ON_WM_LBUTTONDOWN 并记录鼠标按下位置

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);
    //}
}

值得关注的点  

   使用 MeasureItem 设置项目高度对 listctrl 无效。 设置项目高度的一个简单方法是使用图像列表。

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

历史 

在此处持续更新您所做的任何更改或改进。 

© . All rights reserved.