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





5.00/5 (9投票s)
WinCE 上带有透明背景和自定义项目图像的 Ownerdraw listctrl。
简介
下载 ownerDrawList.zip - 4.76 MB
WinCE 上带有透明背景和自定义项目(带有复选框)图像的 Owner-draw listctrl
背景
我正在开发一个媒体播放器,该播放器应在带有自定义硬件的 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 );
历史
在此处持续更新您所做的任何更改或改进。