大家好,又见面了,我是你们的朋友全栈君。
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
DRAWITEMSTRUCT
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制作的效果如图:可以自己设置字体,设置字体颜色,让列表更好看。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/152494.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...