CListCtrl的重绘_clistctrl重绘-程序员宅基地

技术标签: 学习    clistctr  

装载自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
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_43080331/article/details/83145415

智能推荐

计算机网络--第二章物理层_物理层要解决哪些问题-程序员宅基地

文章浏览阅读1.1w次,点赞47次,收藏81次。一.物理层基本概念1.物理层的作用和意义2.物理层的主要任务二、数据通信的基础知识1.数据通信的模型2.信道的几个基本概念2.1串行传输和并行传输2.2同步传输和异步传输2.3通信双方的信息交互方式一.物理层基本概念先强调一下,物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流,而不是指具体的传输媒体,传输媒体不属于计算机网络体系结构的任何一层。1.物理层的作用和意义①物理层是为了解决在各种传输媒体种的0和1问题②物理层的作用是尽可能的屏蔽掉不同传输媒体和通信手段的差异,让物._物理层要解决哪些问题

Usb Hub代码分析_mtk usb hub代码-程序员宅基地

文章浏览阅读1.8k次。如需引用请注明出处:http://blog.csdn.net/zkami 作者:ZhengKui在host controller初始化的时候一定会调用hub_probe进行初始化,至少对root hub初始化hub_probe(struct usb_interface *intf, const struct usb_device_id *id) (hub.c)此时struct us_mtk usb hub代码

Immutable 详解及 React 中实践-程序员宅基地

文章浏览阅读305次。原文链接 请关注我们的专栏Shared mutable state is the root of all evil(共享的可变状态是万恶之源)-- Pete Hunt有人说 Immutable 可以给 React 应用带来数十倍的提升,也有人说 Immutable 的引入是近期 JavaScript 中伟大的发明,因为同期 React 太火,它的光芒被掩盖了。这些至

【排序算法】快速排序原理及Java实现_快速排序java-程序员宅基地

文章浏览阅读10w+次,点赞55次,收藏171次。快速排序是我们之前学习的冒泡排序的升级,他们都属于交换类排序,都是采用不断的比较和移动来实现排序的。快速排序是一种非常高效的排序算法,它的实现,增大了记录的比较和移动的距离,将关键字较大的记录从前面直接移动到后面,关键字较小的记录从后面直接移动到前面,从而减少了总的比较次数和移动次数。同时采用“分而治之”的思想,把大的拆分为小的,小的拆分为更小的,其原理如下:_快速排序java

Qt高级——Qt信号槽机制源码解析-程序员宅基地

文章浏览阅读442次。Qt高级——Qt信号槽机制源码解析基于Qt4.8.6版本一、信号槽机制的原理1、信号槽简介信号槽是观察者模式的一种实现,特性如下:A、一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知;B、一个槽就是一个观察者,通常就是在被观察的对象发生改变的时候——也可以说是信号发出的时候——被调用的函数;C、信号与槽的连接,形成一种观察者-被观察者的关系;D、当事件或者状态发生改变的时...

Computer Science Conference Rankings-程序员宅基地

文章浏览阅读896次。Computer Science Conference RankingsDISCLAIMER:The ranking of conferences are taken mostly from an informal external source. The detailed procedure behind the ranking is unknown

随便推点

买菜用了01 背包 wwwwwwwwwwwwww-程序员宅基地

文章浏览阅读1.7k次。电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。 某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。 Input多组数据。对于每组数据: 第一行为正整数n,表示菜的数...

Linux下的github 添加秘钥出错:Key is invalid. You must supply a key in OpenSSH public key for-程序员宅基地

文章浏览阅读1.3k次。linux下生成秘钥:ssh-keygen -t rsa -C "[email protected]"双引号内是你的github注册地址,所有提示直接回车默认选项就好生成成功后,查看秘钥文件,路径为【~/.ssh/id_rsa.pub】cat ~/.ssh/id_rsa.pub注意:一定是.pub的文件,不是id_rsa文件我一开始用的id_rsa,所以造成标题的报错cat内容:直接复制然后在github中添加秘钥就可以了title随便写,把复制的秘钥粘贴在2格中,然

《C语言点滴》一1.2 程序猿和互联网-程序员宅基地

文章浏览阅读242次。本节书摘来自异步社区《C语言点滴》一书中的第1章,第1.2节,作者 赵岩,更多章节内容可以访问云栖社区“异步社区”公众号查看1.2 程序猿和互联网C语言点滴虽然你可以对电脑的硬件要求不高,但是对另外一个功能还是应该严重关切一下的,那就是联网功能。最方便的联网方式无疑就是3G联网方式了,可以做到随时随地上网。我在北京上班的时候,地铁车厢里有时会有人拿...

Linux内存空间访问札记_kernel dram size-程序员宅基地

文章浏览阅读1.9k次。原文地址:Linux内存空间访问札记 引:本来打算将这部分内容并入到《The Linux Kernel Module Programming Guide笔记》中去,但是想下内存空间管理访问相当基础重要而且内容量较大,所以就单独记录。注:在x86架构上,会分为内存空间和I/O空间,但是在大多数嵌入式控制器如ARM、PowerPC并不提供I/O空间。我面向的主要是嵌入式方面的驱动开发,所_kernel dram size

什么是CSDN_csdn是什么-程序员宅基地

文章浏览阅读758次。如题。是http://blog.csdn.net/Aaron25/category/183631.aspx把我吸引来的。谢谢他。 _csdn是什么

Realme GT2 ROOT 解锁BL教程_gt2工具箱-程序员宅基地

文章浏览阅读6.1k次,点赞3次,收藏14次。Realme GT2 解锁+ROOT教程真我GT2解锁BL 解BL ROOT 刷面具 gt2_gt2工具箱