大家好,又见面了,我是你们的朋友全栈君。
CListCtrl自绘有3种方法:
第一种:使用WM_ERASEBKGND消息 + NM_CUSTOMDRAW消息配合自绘
WM_ERASEBKGND消息中绘制背景色,比如偶数行为灰色,奇数行为白色。
NM_CUSTOMDRAW消息中设置字体的背景色和字体颜色。
好处:保留了控件大多数的原有属性。不需要自己去输出每一个项目的字体。可以非常方便的设置背景色,以及文字的颜色。缺点:不能设置选中行颜色。
使用到2个数据结构:
typedef struct tagNMLVCUSTOMDRAW { NMCUSTOMDRAW nmcd; // 包含客户自绘控件信息的结构 COLORREF clrText; // 列表视图显示文字的颜色 COLORREF clrTextBk; // 列表视图显示文字的背景颜色 } NMLVCUSTOMDRAW, *LPNMLVCUSTOMDRAW; NMCUSTOMDRAW 结构的定义如下: typedef struct tagNMCUSTOMDRAWI { NMHDR hdr; // 含有通知信息的NMHDR结构 DWORD dwDrawStage; // 目前绘制的步骤 HDC hdc; // 设备上下文句柄 RECT rc; // 绘制的区域 DWORD dwItemSpec; // 绘制项的说明 UINT uItemState; // 当前项的状态 LPARAM lItemlParam; // 应用程序定义的数据 } NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW
//先定义2个变量
COLORREF m_colRow1;
COLORREF m_colRow2;
1、添加WM_ERASEBKGND小心
BOOL CColoredListCtrl::OnEraseBkgnd(CDC* pDC) //重载 { CRect rect; CColoredListCtrl::GetClientRect(rect); POINT mypoint; CBrush brush0(m_colRow1); // 颜色1的画笔 CBrush brush1(m_colRow2); // 颜色2的画笔 int chunk_height=GetCountPerPage(); // 得到每页的记录数 pDC->FillRect(&rect,&brush1); // 先用颜色1填充整个客户区 for (int i=0;i<=chunk_height;i++) { GetItemPosition(i,&mypoint); // 得到第i项的位置 rect.top=mypoint.y ; GetItemPosition(i+1,&mypoint); rect.bottom=mypoint.y; pDC->FillRect(&rect,i %2 ? &brush1 : &brush0); // 根据索引的奇偶不同用不同的画刷 } brush0.DeleteObject(); // 删除画笔 brush1.DeleteObject(); return FALSE; }
2、手动添加消息NM_CUSTOMDRAW响应函数
afx_msg void OnCustomDraw( NMHDR * pNotifyStruct, LRESULT * pResult );
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
void CColoredListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) { *pResult=0; LPNMLVCUSTOMDRAW lplvcd=(LPNMLVCUSTOMDRAW)pNMHDR; int iRow=lplvcd->nmcd.dwItemSpec; // 需要绘画的列表项的索引 switch(lplvcd->nmcd.dwDrawStage) // 绘画阶段 {
case CDDS_PREPAINT : // 在绘画前阶段 { *pResult=CDRF_NOTIFYITEMDRAW; // 返回列表项绘画通知 return; } case CDDS_ITEMPREPAINT: // 在列表项的绘画前阶段 { lplvcd->clrText=RGB(0,0,0); *pResult=CDRF_NOTIFYSUBITEMDRAW; // 返回子列表项绘画通知 return; } case CDDS_SUBITEM|CDDS_PREPAINT | CDDS_ITEM:// 绘画列表项或子项 { if(iRow %2) { lplvcd->clrTextBk=m_colRow2; // 奇数项的背景为颜色2 } else { lplvcd->clrTextBk=m_colRow1; // 偶数项的背景为颜色1 } *pResult=CDRF_DODEFAULT; // 控件完成自绘画,不再发送NM_CUSTOMDRAW通知 return; } }
}
第二种:重载WM_PAINT消息,全部自己绘制。新手不推荐。
第三种:重载虚函数virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);将列表的Own Draw Fixel勾上。优点是全部由自己控制,包括字体,字体颜色。背景色,选中色,缺点:有点复杂。
这里面的一个重要的数据结构是:DRAWITEMSTRUCT,参考MSDN
This structure provides information that the owner window must have to determine how to paint an owner-drawn control or menu item.
typedef struct tagDRAWITEMSTRUCT {
UINT CtlType;
UINT CtlID;
UINT itemID;
UINT itemAction;
UINT itemState;
HWND hwndItem;
HDC hDC;
RECT rcItem;
ULONG_PTR itemData;
} DRAWITEMSTRUCT; 我们需要使用到的是ItemID,就是行号,rcItem就是行矩形。
要想知道列号,建立一个CHeaderCtrl*指针,然后就能知道有多少列了。
要想知道某一项的矩形,比如行1,列2的矩形。直接使用GetSubItem(1,2)就可以了。
比如:
void CListCtrlRack::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) {
CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC); CRect rcItem = lpDrawItemStruct->rcItem; CString strText = “”; CFont* pFont = GetFont(); // if ((lpDrawItemStruct->itemState&ODS_FOCUS)) //如果是选中行 { // int nMode = pDC->SetBkMode(TRANSPARENT); rcItem = lpDrawItemStruct->rcItem; rcItem.bottom -= 1; pDC->FillSolidRect(rcItem,RGB(0,255,255)); } else if(lpDrawItemStruct->itemID % 2) //如果是偶数行 { rcItem = lpDrawItemStruct->rcItem; rcItem.bottom -= 1; pDC->FillSolidRect(rcItem,RGB(200,200,200)); } else //如果是奇数行 { rcItem = lpDrawItemStruct->rcItem; rcItem.bottom -= 1; pDC->FillSolidRect(rcItem,RGB(255,255,255)); } lpDrawItemStruct->itemData = LB_SETITEMDATA ; pDC->SelectObject(pFont); for(int i=0;i<GetHeaderCtrl()->GetItemCount();i++) { strText = GetItemText(lpDrawItemStruct->itemID,i); GetSubItemRect(lpDrawItemStruct->itemID,i,LVIR_BOUNDS,rcItem); rcItem.bottom -=1; rcItem.left +=5; pDC->DrawText(strText,strText.GetLength(),&rcItem,DT_LEFT|DT_SINGLELINE|DT_VCENTER); }
}
采用方法3制作的效果如图:可以自己设置字体,设置字体颜色,让列表更好看。


发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/152494.html原文链接:https://javaforall.cn