今天想作一个通用的列表控件, 最好是可以给调用者提供一些,在指定的subitem 上添加各种控件,比如 进度条,编辑框...
下面就开始着手做:
第一步: 设置列表的 onwer draw fixed 属性, 然后重载了
virtual void CListCtrl:: DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
(1) 在 DrawItem F9, 后F5, 我考!!! 程序既然没有中断,怎么我得 DrawItem 没有调用?
我想了一下 这个函数是由父窗口 WM_DRAWITEM 触发的, 然后反射到到各个子控件。
(2) 我在父窗口添加了对 WM_DRAWITEM 的处理,然后在福窗口消息处理函数F9, F5 ,奇怪没有断到。 此时就想不明白了 控件设置了自绘属性 父窗口肯定会接受到自绘制消息的阿。怀疑自己空间属性设置有问题了。 接下来我添加一按钮, 设置了自绘属性。
此时父窗口可以收到 WM_DRAWITEM , 但没有反射到我的列表控件,而是反射到了按钮控件.
(3) 想不通为什么了 我在代码给列表加了几行, 然后运行 呵呵 这次列表类的 DrawItem 居然执行了。
一想, 阿!!!!! 我晕, 列表空件一列行都没有,当然不会自绘拉 晕死了。
现在终于可以自绘拉!!
我找了一下参考代码, 他的大概方式是:
(1) 从 传入参数中得到 当前要绘制的 item ID, 就是第几行
(2) 取得列表的 COLUMN 数
循环:
(3) 对 该 item 的 每个 subItem 绘制,
(4) 取得每个 subitem 的text, 然后 DrawText
循环,end;
有了思路后,我就开始些代码了,写完代码后 一运行 没有任何效果。 我仔细的跟了一遍程序, 里面各个变量值都是合理的, 这就奇怪了。 我有分析了一下看考代码,确认但前思路正确。
发现代码的区别主要是 我用了一个 CMemDC 类, 参考代码直接用的 传入参数中的hdc,然后我的 CMemDC 错了。
我把 CMemDC 在 OnPaint 消息下试验了一下, 没有问题。 然后 自绘 DrawItem 不能用 内存DC,以前没有注意过,今天第一次遇到问题。 好, 那把代码中CMemDC 全部替换为 参数中的DC。 运行程序, 啊!! 果然是不能用内存DC。
一直很纳闷, 然后我又试验了几次,内存DC 可以绘制出来,但是很快就会被刷掉,界面上看不出来的。
那就记住了 在 DrawItem 中最好不用 内存DC
下面是一些代码:
//*************************************************************** void CMyColorList::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { if (!lpDrawItemStruct) return; // 取得DC对象 CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); // 得到列数,子Item数 int m=GetHeaderCtrl()->GetItemCount(); // 对当前行的每个subItem 进行处理 for(int i=0;i<m;i++) { CString str; CRect rcItem; // 得到当前subitem 的Rect 和 文本 GetSubItemRect(lpDrawItemStruct->itemID,i,LVIR_LABEL,rcItem); str=GetItemText(lpDrawItemStruct->itemID,i); // m_ArrayCol 类型 CObArray , 存储ITEM的颜色数组 // 取得该Item对应的颜色 CMyColor *col=(CMyColor *)m_ArrayCol.GetAt(lpDrawItemStruct->itemID); // 绘制 该 subitem pDC->SetBkMode(TRANSPARENT); CBrush brush; brush.CreateSolidBrush(col->colBack); pDC->FillRect(rcItem,&brush); //填充背景色 pDC->SetTextColor(col->colText); // 得到该subItem 状态 LV_ITEM lvi; lvi.mask = LVIF_IMAGE | LVIF_STATE; lvi.iItem = lpDrawItemStruct->itemID; lvi.iSubItem = 0; lvi.stateMask = 0xFFFF; // get all state flags GetItem(&lvi); if((lvi.state & LVIS_SELECTED)||(lvi.state & LVIS_FOCUSED)) // 被选中状态 { if(m_blnSelect) { // 重新绘制背景, 中间深,上下浅的背景 int r1=GetRValue(col->colSelect); int g1=GetGValue(col->colSelect); int b1=GetBValue(col->colSelect); for(int i=rcItem.Height()/2;i>0;i--) { r1=(r1+5)>255?255:(r1+5); g1=(g1+5)>255?255:(g1+5); b1=(b1+5)>255?255:(b1+5); CPen pen(PS_SOLID, 1, RGB(r1, g1, b1)); CPen *old = pDC->SelectObject(&pen); pDC->MoveTo(rcItem.left,rcItem.top+i); pDC->LineTo(rcItem.right,rcItem.top+i); pDC->MoveTo(rcItem.left,rcItem.bottom-i); pDC->LineTo(rcItem.right,rcItem.bottom-i); pDC->SelectObject(old); } } } // 取得每个 Item 对其方式 int nAlign=atoi(m_ArrayHeaderAlign.GetAt(i)); if(i==0&&GetImageList(LVSIL_SMALL)!=NULL) { CPoint ptImage; ptImage.x=rcItem.left; ptImage.y=rcItem.top; GetImageList(LVSIL_SMALL)->Draw(pDC,lvi.iImage,ptImage,ILD_TRANSPARENT); pDC->SetBkMode(TRANSPARENT); rcItem.left=rcItem.left+16; if(nAlign==LVCFMT_LEFT) rcItem.left=rcItem.left+8; } //按照对其方式 绘制文本 switch(nAlign) { case LVCFMT_LEFT: pDC->DrawText(str,rcItem,DT_LEFT); break; case LVCFMT_CENTER: pDC->DrawText(str,rcItem,DT_CENTER); break; case LVCFMT_RIGHT: pDC->DrawText(str,rcItem,DT_RIGHT); break; default: pDC->DrawText(str,rcItem,DT_CENTER); break; } } }