CListCtrl的重绘

装载自http://blog.csdn.net/hurryboylqs/article/details/5858997

自绘一个item我相信大部分人都在10分钟内能搞定

但是绘制非item部分的区域,同学们就傻眼了,不知道如何下手

CListCtrl的绘制机制在windows里做了一个优化,就是一个绘制循环通知过程

之所以不在OnPaint中画是考虑效率上的原因,好了我们看下这个绘制循环:

CDDS_PREERASE 准备开始擦除循环

CDDS_POSTERASE 擦除循环结束

CDDS_PREPAINT 准备开始绘制循环

CDDS_POSTPAINT 绘制循环结束

CDDS_ITEM 指定dwItemSpec, uItemState, lItemlParam参数有效

CDDS_ITEMPREERASE 准备开始列表项擦除

CDDS_ITEMPREPAINT 准备开始列表项绘制

CDDS_SUBITEM 指定列表子项

CDDS_ITEMPOSTERASE 列表项擦除结束

CDDS_ITEMPOSTPAINT 列表项绘制结束

我们这里主要是响应NM_CUSTOMDRAW来实现绘制的

在CDDS_POSTPAINT绘制循环结束时我们可以开始绘制非item的部分,如何计算非item的空间请看下面代码:

。h

#pragma once

// CSkinListCtrl
class CSkinListCtrl : public CListCtrl
{
DECLARE_DYNAMIC(CSkinListCtrl)
public:
unsigned int LIST_ITEM_HEIGHT;
public:
CSkinListCtrl();
virtual ~CSkinListCtrl();
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);
protected:
void Init();
virtual void DrawSubItem(CDC *pDC, int nItem, int nSubItem, CRect &rSubItem, bool bSelected, bool bFocus);
virtual void DrawRemainSpace(LPNMLVCUSTOMDRAW lpnmcd);
virtual void draw_row_bg(CDC *pDC, RECT rc, bool bSelected, bool bFocus,int nRow);
virtual void draw_row_bg(CDC *pDC, RECT rc, bool bSelected, bool bFocus, bool bOdd);
void InvalidateItem(int nItem);
public:
afx_msg void OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult);
virtual void PreSubclassWindow();
virtual void DrawItem(LPDRAWITEMSTRUCT /lpDrawItemStruct/);
};

。cpp
// SkinListCtrl.cpp : implementation file
//
#include “stdafx.h”
#include “SkinListCtrl.h”
// CSkinListCtrl
IMPLEMENT_DYNAMIC(CSkinListCtrl, CListCtrl)
CSkinListCtrl::CSkinListCtrl()
{
LIST_ITEM_HEIGHT = 20;
}
CSkinListCtrl::~CSkinListCtrl()
{
}

BEGIN_MESSAGE_MAP(CSkinListCtrl, CListCtrl)
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CSkinListCtrl::OnNMCustomdraw)
//ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, &CSkinListCtrl::OnLvnItemchanged)
END_MESSAGE_MAP()

// CSkinListCtrl message handlers
void CSkinListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLVCUSTOMDRAW lpnmcd = (LPNMLVCUSTOMDRAW) pNMHDR;
if (lpnmcd ->nmcd.dwDrawStage == CDDS_PREPAINT)
{
*pResult = CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT;
return;
}
else if (lpnmcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
{
/CRect rSubItem, rectClient;
GetItemRect(lpnmcd->nmcd.dwItemSpec, &rSubItem, LVIR_LABEL);
GetClientRect(&rectClient);
rSubItem.left = 0;
rSubItem.right = rectClient.right;
rSubItem.NormalizeRect();
bool bSelected = false;
if (GetItemState(lpnmcd->nmcd.dwItemSpec, LVIS_SELECTED))
{
bSelected = true;
}
bool bFocus = false;
HWND hWndFocus = ::GetFocus();
if (::IsChild(m_hWnd,hWndFocus) || m_hWnd == hWndFocus)
{
bFocus = true;
}
CDC dc;
dc.Attach(lpnmcd->nmcd.hdc);
draw_row_bg(&dc, rSubItem, bSelected , bFocus, (int) lpnmcd->nmcd.dwItemSpec);
dc.Detach();
/
*pResult = CDRF_NOTIFYSUBITEMDRAW;
return;
}
else if (lpnmcd ->nmcd.dwDrawStage == (CDDS_SUBITEM | CDDS_ITEMPREPAINT))
{
int iItem = lpnmcd->nmcd.dwItemSpec;
int iSubItem = lpnmcd->iSubItem;
if (iItem >= 0 && iSubItem >= 0)
{
CRect rSubItem;
HDC hDC = lpnmcd->nmcd.hdc;
GetSubItemRect(iItem, iSubItem, LVIR_LABEL,rSubItem);
if (iSubItem == 0)
{
rSubItem.left = 0;
}

		bool bSelected = false;
		if (GetItemState(iItem, LVIS_SELECTED))
		{
			bSelected = true;
		}
		bool bFocus = false;
		CWnd *pWndFocus = GetFocus();
		if (IsChild(pWndFocus) || pWndFocus == this)
		{
			bFocus = true;
		}
		rSubItem.NormalizeRect();
		CDC dc;
		dc.Attach(lpnmcd->nmcd.hdc);
		DrawSubItem(&dc,iItem,iSubItem,rSubItem,bSelected,bFocus);
		dc.Detach();
		*pResult =  CDRF_SKIPDEFAULT;
		return;
	}
}
else if (lpnmcd ->nmcd.dwDrawStage == CDDS_POSTPAINT)
{
	DrawRemainSpace(lpnmcd);
	*pResult =  CDRF_SKIPDEFAULT;
	return;
}
 
*pResult = 0;

}
// overwrite:
void CSkinListCtrl::DrawSubItem(CDC *pDC, int nItem, int nSubItem, CRect &rSubItem, bool bSelected, bool bFocus)
{

pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(RGB(0, 0, 0));
CFont font;
font.CreateFont(12,   // nHeight
	0,                         // nWidth
	0,                         // nEscapement
	0,                         // nOrientation
	FW_NORMAL,                 // nWeight
	FALSE,                     // bItalic
	FALSE,                     // bUnderline
	0,                         // cStrikeOut
	ANSI_CHARSET,              // nCharSet
	OUT_DEFAULT_PRECIS,        // nOutPrecision
	CLIP_DEFAULT_PRECIS,       // nClipPrecision
	DEFAULT_QUALITY,           // nQuality
	DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
	_T("宋体"));
pDC->SelectObject(&font);
CString strText;
strText = GetItemText(nItem, nSubItem);
draw_row_bg(pDC, rSubItem, bSelected, bFocus, nItem);
pDC->DrawText(strText, strText.GetLength(), &rSubItem, DT_SINGLELINE | DT_RIGHT | DT_VCENTER | DT_END_ELLIPSIS);

}
// 画剩余部分
void CSkinListCtrl::DrawRemainSpace(LPNMLVCUSTOMDRAW lpnmcd)
{
int nTop = lpnmcd->nmcd.rc.top;
int nCount = GetItemCount();
if (nCount > 0)
{
CRect rcItem;
GetItemRect(nCount - 1, &rcItem, LVIR_LABEL);
nTop = rcItem.bottom;
}
CRect rectClient;
GetClientRect(&rectClient);
if (nTop < lpnmcd->nmcd.rc.bottom) // 有剩余
{
CRect rcRemain = lpnmcd->nmcd.rc;
rcRemain.top = nTop;
rcRemain.right = rectClient.right;
int nRemainItem = rcRemain.Height() / LIST_ITEM_HEIGHT;
if (rcRemain.Height() % LIST_ITEM_HEIGHT)
{
nRemainItem++;
}
int pos = GetScrollPos(SB_HORZ);
CDC dc;
dc.Attach(lpnmcd->nmcd.hdc);
for (int i = 0; i < nRemainItem; ++i)
{
CRect rcItem;
rcItem.top = rcRemain.top + i * LIST_ITEM_HEIGHT;
rcItem.left = rcRemain.left;
rcItem.right = rcRemain.right;
rcItem.bottom = rcItem.top + LIST_ITEM_HEIGHT;
int nColumnCount = GetHeaderCtrl()->GetItemCount();
CRect rcSubItem;
for (int j = 0; j < nColumnCount; ++j)
{
GetHeaderCtrl()->GetItemRect(j, &rcSubItem);
rcSubItem.top = rcItem.top;
rcSubItem.bottom = rcItem.bottom;
rcSubItem.OffsetRect(-pos, 0);
if(rcSubItem.right < rcRemain.left || rcSubItem.left > rcRemain.right)
continue;
draw_row_bg(&dc, rcSubItem, false, false, i + nCount);
}
/if (rcSubItem.right<rectClient.right)
{
rcSubItem.left=rcSubItem.right;
rcSubItem.right=rectClient.right;
draw_row_bg(&dc, rcSubItem, false, false, i+nCount);
}
/
}
dc.Detach();
}
}
void CSkinListCtrl::draw_row_bg(CDC *pDC, RECT rc, bool bSelected, bool bFocus,int nRow)
{
bool bOdd = (nRow % 2 == 0 ? true : false);
CRect rect = rc;
if (rect.Width() == 0)
{
return;
}

draw_row_bg(pDC, rc, bSelected,bFocus,bOdd);

}
void CSkinListCtrl::draw_row_bg(CDC *pDC, RECT rc, bool bSelected, bool bFocus, bool bOdd)
{
CRect rect = rc;
if (rect.Width() == 0)
{
return;
}
int nSave = pDC->SaveDC();
if (bSelected)
{
if (bFocus)
{
CBrush selectBrush;
selectBrush.CreateSolidBrush(RGB(203, 223, 239));
pDC->FillRect(&rc, &selectBrush);
}
else
{
CBrush selectNoFocusBrush;
selectNoFocusBrush.CreateSolidBrush(RGB(206, 206, 206));
pDC->FillRect(&rc, &selectNoFocusBrush);
}
}
else if (bOdd)
{
CBrush oddBrush;
oddBrush.CreateSolidBrush(RGB(255, 255, 255));
pDC->FillRect(&rc, &oddBrush);
}
else
{
CBrush normalBrush;
normalBrush.CreateSolidBrush(RGB(243, 243, 243));
pDC->FillRect(&rc, &normalBrush);
}

// 画竖线
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(218, 218, 218));
pDC->SelectObject(&pen);
pDC->MoveTo(rc.right - 1, rc.top);
pDC->LineTo(rc.right - 1, rc.bottom);
// 画选中的底部分割线
if (bSelected)
{
	CPen bottomPen;
	bottomPen.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
	pDC->SelectObject(&bottomPen);
	pDC->MoveTo(rc.left, rc.bottom - 1);
	pDC->LineTo(rc.right, rc.bottom - 1);
}
pDC->RestoreDC(nSave);

}
void CSkinListCtrl::Init()
{
LOGFONT logfont;
memset(&logfont, 0, sizeof(logfont));
logfont.lfWeight = FW_NORMAL;
logfont.lfCharSet = GB2312_CHARSET;
_tcscpy_s(logfont.lfFaceName, LF_FACESIZE, _T(“宋体”));
logfont.lfHeight = -(LIST_ITEM_HEIGHT-1);
CFont font;
font.CreateFontIndirect(&logfont);
SetFont(&font);
font.Detach();
}
void CSkinListCtrl::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR);
if (pNMLV->uChanged & LVIF_STATE)
{
if (((pNMLV->uOldState & LVIS_SELECTED) != (pNMLV->uNewState & LVIS_SELECTED))
|| ((pNMLV->uOldState & LVIS_STATEIMAGEMASK) != (pNMLV->uNewState & LVIS_STATEIMAGEMASK)))
{
InvalidateItem(pNMLV->iItem);
}
}
*pResult = 0;
}
void CSkinListCtrl::InvalidateItem(int nItem)
{
CRect rcClient;
GetClientRect(&rcClient);
CRect rcItem;
GetItemRect(nItem, &rcItem, LVIR_BOUNDS);
rcItem.left = rcClient.left;
rcItem.right = rcClient.right;
InvalidateRect(&rcItem,FALSE);
}
void CSkinListCtrl::PreSubclassWindow()
{
Init();
CListCtrl::PreSubclassWindow();
}
void CSkinListCtrl::DrawItem(LPDRAWITEMSTRUCT /lpDrawItemStruct/)
{
}

看到了吧 ,非item部分我们也绘制出来了,右边问号部分我这里没做绘制,这部分也可以绘制的,可以把斑马线顶到最右边

创建CListCtrl时样式建议如下:

DWORD dwExtentStyle = m_list.GetExtendedStyle();
m_list.SetExtendedStyle(dwExtentStyle|LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER);

这里已经画有网格线进去了,样式里就不要加这个网格线样式了,就是不用LVS_EX_GRIDLINES样式

OK,后面我们再来画下headerctrl就很好看了,下一篇中给出源码,并结合到CSkinListCtrl中。

上篇自绘了CListCtrl,做得大体上差不多了,但是CHeaderCtrl没有绘制,右边非column部分也没将网格线顶到头,实在是一个小遗憾

这里一并将CHeaderCtrl绘制了而且斑马线也画到最右边,

使用这个listctrl的时候只需这样子设置,就可以获得很好的效果:

DWORD dwExtentStyle = m_list.GetExtendedStyle();
m_list.SetExtendedStyle(dwExtentStyle|LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER);

SkinListCtrl.h
#pragma once
#include “SkinHeaderCtrl.h”

// CSkinListCtrl

class CSkinListCtrl : public CListCtrl
{
DECLARE_DYNAMIC(CSkinListCtrl)
public:
unsigned int LIST_ITEM_HEIGHT;
public:
CSkinListCtrl();
virtual ~CSkinListCtrl();

protected:
DECLARE_MESSAGE_MAP()
protected:
void Init();
virtual void DrawSubItem(CDC *pDC, int nItem, int nSubItem, CRect &rSubItem, bool bSelected, bool bFocus);
virtual void DrawRemainSpace(LPNMLVCUSTOMDRAW lpnmcd);
virtual void draw_row_bg(CDC *pDC, RECT rc, bool bSelected, bool bFocus,int nRow);
virtual void draw_row_bg(CDC *pDC, RECT rc, bool bSelected, bool bFocus, bool bOdd);
void InvalidateItem(int nItem);
public:
afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnHdnItemchanged(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnLvnEndScroll(NMHDR *pNMHDR, LRESULT *pResult);
virtual void PreSubclassWindow();
virtual void DrawItem(LPDRAWITEMSTRUCT /lpDrawItemStruct/);
private:
CSkinHeaderCtrl m_header;
};

SkinListCtrl.cpp
// SkinListCtrl.cpp : implementation file
//

#include “stdafx.h”
#include “TopMost.h”
#include “SkinListCtrl.h”

// CSkinListCtrl

IMPLEMENT_DYNAMIC(CSkinListCtrl, CListCtrl)

CSkinListCtrl::CSkinListCtrl()
{
LIST_ITEM_HEIGHT = 20;
}

CSkinListCtrl::~CSkinListCtrl()
{
}

BEGIN_MESSAGE_MAP(CSkinListCtrl, CListCtrl)
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CSkinListCtrl::OnNMCustomdraw)
ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, &CSkinListCtrl::OnLvnItemchanged)
ON_NOTIFY(HDN_ITEMCHANGEDA, 0, &CSkinListCtrl::OnHdnItemchanged)
ON_NOTIFY(HDN_ITEMCHANGEDW, 0, &CSkinListCtrl::OnHdnItemchanged)
ON_NOTIFY_REFLECT(LVN_ENDSCROLL, &CSkinListCtrl::OnLvnEndScroll)
END_MESSAGE_MAP()

// CSkinListCtrl message handlers

void CSkinListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{

LPNMLVCUSTOMDRAW lpnmcd = (LPNMLVCUSTOMDRAW) pNMHDR;
if (lpnmcd ->nmcd.dwDrawStage == CDDS_PREPAINT)
{
	*pResult =  CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT;
	return;
}
else if (lpnmcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
{
	CRect rSubItem, rectClient;
	int nColumnCount = GetHeaderCtrl()->GetItemCount();
	if (nColumnCount>0)
	{
		GetSubItemRect(lpnmcd->nmcd.dwItemSpec,nColumnCount-1, LVIR_LABEL,rSubItem);
		GetClientRect(&rectClient);	
		rSubItem.left = rSubItem.right;
		rSubItem.right = rectClient.right;
		rSubItem.NormalizeRect();
		bool bSelected = false;
		if (GetItemState(lpnmcd->nmcd.dwItemSpec, LVIS_SELECTED))
		{
			bSelected = true;
		}

		bool bFocus = false;
		HWND hWndFocus = ::GetFocus();
		if (::IsChild(m_hWnd,hWndFocus) || m_hWnd == hWndFocus)
		{
			bFocus = true;
		}
		CDC dc;
		dc.Attach(lpnmcd->nmcd.hdc);
		draw_row_bg(&dc, rSubItem, bSelected , bFocus, (int) lpnmcd->nmcd.dwItemSpec);
		dc.Detach();
	}

	*pResult =  CDRF_NOTIFYSUBITEMDRAW;
	return;
}
else if (lpnmcd ->nmcd.dwDrawStage == (CDDS_SUBITEM | CDDS_ITEMPREPAINT))
{
	int iItem = lpnmcd->nmcd.dwItemSpec;
	int iSubItem = lpnmcd->iSubItem;
	if (iItem >= 0 && iSubItem >= 0)
	{
		CRect rSubItem;
		HDC hDC = lpnmcd->nmcd.hdc;
		GetSubItemRect(iItem, iSubItem, LVIR_LABEL,rSubItem);
		if (iSubItem == 0)
		{
			rSubItem.left = 0;
		}
		
		bool bSelected = false;
		if (GetItemState(iItem, LVIS_SELECTED))
		{
			bSelected = true;
		}

		bool bFocus = false;
		CWnd *pWndFocus = GetFocus();
		if (IsChild(pWndFocus) || pWndFocus == this)
		{
			bFocus = true;
		}

		rSubItem.NormalizeRect();
		CDC dc;
		dc.Attach(lpnmcd->nmcd.hdc);
		DrawSubItem(&dc,iItem,iSubItem,rSubItem,bSelected,bFocus);
		dc.Detach();
		*pResult =  CDRF_SKIPDEFAULT;
		return;
	}
}
else if (lpnmcd ->nmcd.dwDrawStage == CDDS_POSTPAINT)
{
	DrawRemainSpace(lpnmcd);
	*pResult =  CDRF_SKIPDEFAULT;
	return;
}
 
*pResult = 0;

}

// overwrite:
void CSkinListCtrl::DrawSubItem(CDC *pDC, int nItem, int nSubItem, CRect &rSubItem, bool bSelected, bool bFocus)
{

pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(RGB(0, 0, 0));

CFont font;
font.CreateFont(12,   // nHeight
	0,                         // nWidth
	0,                         // nEscapement
	0,                         // nOrientation
	FW_NORMAL,                 // nWeight
	FALSE,                     // bItalic
	FALSE,                     // bUnderline
	0,                         // cStrikeOut
	ANSI_CHARSET,              // nCharSet
	OUT_DEFAULT_PRECIS,        // nOutPrecision
	CLIP_DEFAULT_PRECIS,       // nClipPrecision
	DEFAULT_QUALITY,           // nQuality
	DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
	_T("宋体"));
pDC->SelectObject(&font);

CString strText;
strText = GetItemText(nItem, nSubItem);
draw_row_bg(pDC, rSubItem, bSelected, bFocus, nItem);
pDC->DrawText(strText, strText.GetLength(), &rSubItem, DT_SINGLELINE | DT_RIGHT | DT_VCENTER | DT_END_ELLIPSIS);

}

// 画剩余部分
void CSkinListCtrl::DrawRemainSpace(LPNMLVCUSTOMDRAW lpnmcd)
{
int nTop = lpnmcd->nmcd.rc.top;
int nCount = GetItemCount();
if (nCount > 0)
{
CRect rcItem;
GetItemRect(nCount - 1, &rcItem, LVIR_LABEL);
nTop = rcItem.bottom;
}

CRect rectClient;
GetClientRect(&rectClient);
if (nTop < lpnmcd->nmcd.rc.bottom) // 有剩余
{
	CRect rcRemain = lpnmcd->nmcd.rc;
	rcRemain.top = nTop;
	rcRemain.right = rectClient.right;
	int nRemainItem = rcRemain.Height() / LIST_ITEM_HEIGHT;
	if (rcRemain.Height() % LIST_ITEM_HEIGHT)
	{
		nRemainItem++;
	}

	int pos = GetScrollPos(SB_HORZ);
	CDC dc;
	dc.Attach(lpnmcd->nmcd.hdc);
	int nColumnCount = GetHeaderCtrl()->GetItemCount();
	CRect  rcSubItem;
	CRect rcItem;
	for (int i = 0; i < nRemainItem; ++i)
	{
		
		rcItem.top = rcRemain.top + i * LIST_ITEM_HEIGHT;
		rcItem.left = rcRemain.left;
		rcItem.right = rcRemain.right;
		rcItem.bottom = rcItem.top + LIST_ITEM_HEIGHT;
		for (int j = 0; j < nColumnCount; ++j)
		{
			GetHeaderCtrl()->GetItemRect(j, &rcSubItem);
			rcSubItem.top = rcItem.top;
			rcSubItem.bottom = rcItem.bottom;
			rcSubItem.OffsetRect(-pos, 0);
			if(rcSubItem.right < rcRemain.left || rcSubItem.left > rcRemain.right)
				continue;
			draw_row_bg(&dc, rcSubItem, false, false, i + nCount);			
		}
		if (rcSubItem.right<rectClient.right)
		{
			rcSubItem.left=rcSubItem.right;
			rcSubItem.right=rectClient.right;
            draw_row_bg(&dc, rcSubItem, false, false, i+nCount);	
		}
	}
	dc.Detach();
}

}
void CSkinListCtrl::draw_row_bg(CDC *pDC, RECT rc, bool bSelected, bool bFocus,int nRow)
{
bool bOdd = (nRow % 2 == 0 ? true : false);
CRect rect = rc;
if (rect.Width() == 0)
{
return;
}

draw_row_bg(pDC, rc, bSelected,bFocus,bOdd);

}
void CSkinListCtrl::draw_row_bg(CDC *pDC, RECT rc, bool bSelected, bool bFocus, bool bOdd)
{
CRect rect = rc;
if (rect.Width() == 0)
{
return;
}
int nSave = pDC->SaveDC();
if (bSelected)
{
if (bFocus)
{
CBrush selectBrush;
selectBrush.CreateSolidBrush(RGB(203, 223, 239));
pDC->FillRect(&rc, &selectBrush);

	}
	else
	{
		CBrush selectNoFocusBrush;
		selectNoFocusBrush.CreateSolidBrush(RGB(206, 206, 206));
		pDC->FillRect(&rc, &selectNoFocusBrush);
	}
}
else if (bOdd)
{
	CBrush oddBrush;
	oddBrush.CreateSolidBrush(RGB(255, 255, 255));
	pDC->FillRect(&rc, &oddBrush);

}
else
{
	CBrush normalBrush;
	normalBrush.CreateSolidBrush(RGB(243, 243, 243));
	pDC->FillRect(&rc, &normalBrush);
}


// 画竖线
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(218, 218, 218));

pDC->SelectObject(&pen);
pDC->MoveTo(rc.right - 1, rc.top);
pDC->LineTo(rc.right - 1, rc.bottom);

// 画选中的底部分割线
if (bSelected)
{
	CPen bottomPen;
	bottomPen.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));

	pDC->SelectObject(&bottomPen);
	pDC->MoveTo(rc.left, rc.bottom - 1);
	pDC->LineTo(rc.right, rc.bottom - 1);
}

pDC->RestoreDC(nSave);

}

void CSkinListCtrl::Init()
{
CHeaderCtrl *pHeaderCtrl = GetHeaderCtrl();
if (pHeaderCtrl!=NULL)
{
m_header.SubclassWindow(pHeaderCtrl->GetSafeHwnd());
}
LOGFONT logfont;
memset(&logfont, 0, sizeof(logfont));
logfont.lfWeight = FW_NORMAL;
logfont.lfCharSet = GB2312_CHARSET;
_tcscpy_s(logfont.lfFaceName, LF_FACESIZE, _T(“宋体”));
logfont.lfHeight = -(LIST_ITEM_HEIGHT-1);
CFont font;
font.CreateFontIndirect(&logfont);
SetFont(&font);
font.Detach();
}

void CSkinListCtrl::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
Invalidate();
*pResult = 0;
}

void CSkinListCtrl::InvalidateItem(int nItem)
{
CRect rcClient;
GetClientRect(&rcClient);

CRect rcItem;
GetItemRect(nItem, &rcItem, LVIR_BOUNDS);

rcItem.left = rcClient.left;
rcItem.right = rcClient.right;
InvalidateRect(&rcItem,FALSE);

}

void CSkinListCtrl::PreSubclassWindow()
{
Init();
CListCtrl::PreSubclassWindow();
}

void CSkinListCtrl::DrawItem(LPDRAWITEMSTRUCT /lpDrawItemStruct/)
{

}

void CSkinListCtrl::OnHdnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMHEADER phdr = reinterpret_cast(pNMHDR);
Default();
Invalidate();
*pResult = 0;
}

void CSkinListCtrl::OnLvnEndScroll(NMHDR *pNMHDR, LRESULT *pResult)
{
// 此功能要求 Internet Explorer 5.5 或更高版本。
// 符号 _WIN32_IE 必须是 >= 0x0560。
LPNMLVSCROLL pStateChanged = reinterpret_cast(pNMHDR);
Invalidate();
*pResult = 0;
}

SkinHeaderCtrl.h
#pragma once

enum
{
_nSortNone = 0,
_nSortUp,
_nSortDown,

_nSortCount = 3,

};

// CSkinHeaderCtrl

class CSkinHeaderCtrl : public CHeaderCtrl
{
DECLARE_DYNAMIC(CSkinHeaderCtrl)

public:
CSkinHeaderCtrl();
virtual ~CSkinHeaderCtrl();
public:
void SetItemSortState(int iItem, UINT sortState);
UINT GetItemSortState(int iItem);

protected:
DECLARE_MESSAGE_MAP()
afx_msg LRESULT OnLayout(WPARAM wParam,LPARAM lParam);
private:
void Init();
public:
afx_msg void OnPaint();
virtual void DoPaint(CDC *pDC);
protected:
virtual void PreSubclassWindow();
public:
afx_msg void OnHdnItemchanged(NMHDR *pNMHDR, LRESULT pResult);
afx_msg BOOL OnEraseBkgnd(CDC
pDC);
virtual void DrawItem(LPDRAWITEMSTRUCT /lpDrawItemStruct/);
};

SkinHeaderCtrl.cpp
// SkinHeaderCtrl.cpp : implementation file
//

#include “stdafx.h”
#include “TopMost.h”
#include “SkinHeaderCtrl.h”
#include <atlbase.h>
#include <atlimage.h>

// CSkinHeaderCtrl

IMPLEMENT_DYNAMIC(CSkinHeaderCtrl, CHeaderCtrl)

CSkinHeaderCtrl::CSkinHeaderCtrl()
{

}

CSkinHeaderCtrl::~CSkinHeaderCtrl()
{
}

BEGIN_MESSAGE_MAP(CSkinHeaderCtrl, CHeaderCtrl)
ON_MESSAGE(HDM_LAYOUT,OnLayout)
ON_WM_PAINT()
//ON_NOTIFY(HDN_ITEMCHANGEDA, 0, &CSkinHeaderCtrl::OnHdnItemchanged)
//ON_NOTIFY(HDN_ITEMCHANGEDW, 0, &CSkinHeaderCtrl::OnHdnItemchanged)
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

// CSkinHeaderCtrl message handlers
void CSkinHeaderCtrl::SetItemSortState(int iItem, UINT sortState)
{
ASSERT(sortState == _nSortUp || sortState == _nSortUp || sortState == _nSortDown);
ASSERT(m_hWnd != NULL && IsWindow(m_hWnd));

int nItemCount = GetItemCount();
ASSERT(iItem >= 0 && iItem < nItemCount);
HDITEM hditem;
hditem.mask = HDI_FORMAT;
GetItem(iItem, &hditem);
if (sortState == _nSortUp)
{
	hditem.fmt &= ~HDF_SORTDOWN;
	hditem.fmt |= HDF_SORTUP;
}
else
{
	hditem.fmt &= ~HDF_SORTUP;
	hditem.fmt |= HDF_SORTDOWN;
}
SetItem(iItem, &hditem);
CRect rect;
GetItemRect(iItem, &rect);
InvalidateRect(&rect);

}
UINT CSkinHeaderCtrl::GetItemSortState(int iItem)
{
ASSERT(m_hWnd != NULL && IsWindow(m_hWnd));
int nItemCount = GetItemCount();
ASSERT(iItem >= 0 && iItem < nItemCount);
HDITEM hditem;
hditem.mask = HDI_FORMAT;
GetItem(iItem, &hditem);
if (hditem.fmt & HDF_SORTUP)
{
return _nSortUp;
}
else if (hditem.fmt & HDF_SORTDOWN)
{
return _nSortDown;
}
else
{
return _nSortNone;
}
}
LRESULT CSkinHeaderCtrl::OnLayout(WPARAM wParam,LPARAM lParam)
{
LRESULT lResult = CHeaderCtrl::DefWindowProc(HDM_LAYOUT, 0, lParam);
HD_LAYOUT &hdl = *(HD_LAYOUT *) lParam;
RECT *prc = hdl.prc;
WINDOWPOS *pwpos = hdl.pwpos;
pwpos->cy = 22;
prc->top = 22;
return lResult;
}

void CSkinHeaderCtrl::Init()
{
ModifyStyle(0, HDS_FLAT);
}

void CSkinHeaderCtrl::OnPaint()
{
CPaintDC dc(this); // device context for painting
DoPaint(&dc);
}

void CSkinHeaderCtrl::DoPaint(CDC *pDC)
{
CRect rect, rcItem;
GetClientRect(&rect);

CDC memDC;
CBitmap bmp;
memDC.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
memDC.SelectObject(&bmp);

memDC.SetBkMode(TRANSPARENT);
memDC.SetTextColor(RGB(0, 0, 0));
memDC.SetStretchBltMode(HALFTONE);

LOGFONT logfont;
memset(&logfont, 0x0, sizeof(logfont));
logfont.lfHeight = 12;
logfont.lfWeight = FW_NORMAL;
logfont.lfCharSet = GB2312_CHARSET;
_tcscpy_s(logfont.lfFaceName, LF_FACESIZE, _T("宋体"));

CFont font;
font.CreateFontIndirect(&logfont);
memDC.SelectObject(&font);

// 填充背景
CImage image;
image.LoadFromResource(AfxGetResourceHandle(), IDB_HEADERCTRL_SPAN_NORMAL);
image.Draw(memDC, rect);
image.Destroy();

int nItems = GetItemCount();
for (int i = 0; i < nItems; ++i)
{
	TCHAR buf[256];
	HDITEM hditem;
	hditem.mask = HDI_TEXT | HDI_FORMAT | HDI_ORDER;
	hditem.pszText = buf;
	hditem.cchTextMax = 255;
	GetItem(i, &hditem);
	GetItemRect(i, &rcItem);
	if (rcItem.IsRectEmpty())
	{
		continue;
	}
	// 画分割线
	image.LoadFromResource(AfxGetResourceHandle(), IDB_HEADERCTRL_END_NORMAL);
	image.Draw(memDC, rcItem.right - 1, rcItem.top);
	image.Destroy();
	// 画文字和排序箭头
	UINT uFormat = DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX;
	if (hditem.fmt & HDF_RIGHT)
	{
		uFormat |= DT_RIGHT;
	}
	else if (hditem.fmt & HDF_CENTER)
	{
		uFormat |= DT_CENTER;
	}
	CRect rcText = rcItem;
	if ((hditem.fmt & HDF_SORTUP) | (hditem.fmt & HDF_SORTDOWN))
	{
		rcText.DeflateRect(5, 1, 13, 1);
		memDC.DrawText(buf, static_cast<int> (_tcslen(buf)), &rcText, uFormat);
	}
	else
	{
		rcText.DeflateRect(5, 1, 5, 1);
		memDC.DrawText(buf, static_cast<int>(_tcslen(buf)), &rcText, uFormat);
	}
}

pDC->BitBlt(0,0,rect.Width(),rect.Height(),&memDC,0,0,SRCCOPY);

}

void CSkinHeaderCtrl::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
Init();
CHeaderCtrl::PreSubclassWindow();
}

void CSkinHeaderCtrl::OnHdnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMHEADER phdr = reinterpret_cast(pNMHDR);
//Invalidate();
*pResult = 0;
}

BOOL CSkinHeaderCtrl::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE;
return CHeaderCtrl::OnEraseBkgnd(pDC);
}

void CSkinHeaderCtrl::DrawItem(LPDRAWITEMSTRUCT /lpDrawItemStruct/)
{
Invalidate();
// TODO: Add your code to draw the specified item
}

猜你喜欢

转载自blog.csdn.net/qq_43080331/article/details/83145415
今日推荐