【MFC】控件自绘之CListCtrl

一:

   国际惯例,直接上代码

 

二:

.h头文件

// CSkinHeaderCtrl
class CSkinHeaderCtrl : public CHeaderCtrl
{
	DECLARE_DYNAMIC(CSkinHeaderCtrl)

public:
	CSkinHeaderCtrl();
	virtual ~CSkinHeaderCtrl();

	void SetHeaderBk(CString strBkImage);
protected:
	DECLARE_MESSAGE_MAP()

	afx_msg void OnPaint();
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg LRESULT OnLayout( WPARAM wParam, LPARAM lParam );

	virtual void PreSubclassWindow();

	void DrawColumn(CDC* pDC, int nIndex);
	void DrawBackGnd(CDC* pDC);

private:
	Image*					m_pBkImage;
};

// CSkinListCtrl

class CSkinListCtrl : public CListCtrl
{
	DECLARE_DYNAMIC(CSkinListCtrl)

public:
	CSkinListCtrl();
	virtual ~CSkinListCtrl();

	void SetRowHeight(int nHeight);

	virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
	DECLARE_MESSAGE_MAP()

	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);

	virtual void PreSubclassWindow();

	void DrawEveryone(CDC* pDC, int nItem, int nSubItem);

private:
	enum
	{
		TEXT_ALIGN_LEFT = 0,
		TEXT_ALIGN_CENTER,
		TEXT_ALIGN_RIGHT
	};

	enum
	{
		ITEM_UNKNOWN = 0,
		ITEM_SELECTED,
		ITEM_FOCUSED,
	};

	int GetTextAlign(int nColumn);
	int GetItemState(int nItem, int nSubItem);

private:
	CSkinHeaderCtrl      m_HeaderCtrl;              //列表头控件
	int                  m_nCurSelItem;             //当前选中项
	int					 m_nRowHeight;              //行高
};


 

.cpp源文件

// CSkinHeaderCtrl
IMPLEMENT_DYNAMIC(CSkinHeaderCtrl, CHeaderCtrl)

CSkinHeaderCtrl::CSkinHeaderCtrl():
m_pBkImage(NULL)
{
	SetHeaderBk(_T("..//Skin//ListHeaderBK.png"));
}

CSkinHeaderCtrl::~CSkinHeaderCtrl()
{
	if(m_pBkImage)
	{
		delete m_pBkImage;
		m_pBkImage = NULL;
	}
}

BEGIN_MESSAGE_MAP(CSkinHeaderCtrl, CHeaderCtrl)
	ON_WM_SIZE()
	ON_WM_PAINT()
	ON_MESSAGE(HDM_LAYOUT, OnLayout)
END_MESSAGE_MAP()

void CSkinHeaderCtrl::SetHeaderBk(CString strBkImage)
{
	ASSERT(m_pBkImage == NULL);

	m_pBkImage = Image::FromFile(strBkImage);
}

void CSkinHeaderCtrl::DrawColumn(CDC* pDC, int nIndex)
{
	CRect                    rect;

	//获取区域小矩形
	GetItemRect(nIndex, &rect);
	HDITEM hdi;
	const int c_cchBuffer = 256;
	TCHAR  lpBuffer[c_cchBuffer];

	hdi.mask = HDI_TEXT;
	hdi.pszText = lpBuffer;
	hdi.cchTextMax = c_cchBuffer;

	VERIFY(GetItem(nIndex, &hdi));


	CString                  strItemText(lpBuffer);
	Graphics                 graph(pDC->m_hDC);
	RectF                    rectF(rect.left, rect.top, rect.Width(), rect.Height());

	TextureBrush texBrush(m_pBkImage);

	graph.FillRectangle(&texBrush, rectF);
	graph.DrawRectangle(&Pen(Color::White), rectF);

	FontFamily fontFamily(L"微软雅黑");
	Gdiplus::Font       font(&fontFamily, 10, FontStyleBold, UnitPoint);

	SolidBrush solidBrush(Color::Black);
	StringFormat stringFormat;
	stringFormat.SetLineAlignment(StringAlignmentCenter);
	stringFormat.SetAlignment(StringAlignmentNear);
	stringFormat.SetFormatFlags(StringFormatFlagsLineLimit ); //限制一行
	rectF.X += 10.0f;  //不要完全靠左 不好看

	//画文字和按钮
	graph.DrawString(strItemText, strItemText.GetLength(), &font, rectF, &stringFormat, &solidBrush);
}

void CSkinHeaderCtrl::DrawBackGnd(CDC* pDC)
{
	CRect rect;
	GetClientRect(&rect);

	Graphics                 graph(pDC->m_hDC);
	RectF                    rectF(rect.left, rect.top, rect.Width(), rect.Height());
	TextureBrush			 texBrush(m_pBkImage);

	graph.FillRectangle(&texBrush, rectF);
}

void CSkinHeaderCtrl::OnPaint()
{
	CPaintDC dc(this);
	CRect    rect;
	GetClientRect(&rect);
	
	CMemDCC  DCMemory(&dc, &rect);
	DrawBackGnd(&DCMemory);
	//计算一共有多少列,绘制每一列
	int nCount = GetItemCount();
	for(int i= 0; i<nCount; i++)
	{
		DrawColumn(&DCMemory, i);
	}
}

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 = m_pBkImage->GetHeight(); 
	prc->top = m_pBkImage->GetHeight(); 
	return lResult; 
}

void CSkinHeaderCtrl::PreSubclassWindow()
{
	CHeaderCtrl::PreSubclassWindow();

}

void CSkinHeaderCtrl::OnSize(UINT nType, int cx, int cy)
{
	CHeaderCtrl::OnSize(nType, cx, cy);

	Invalidate();
}

// CSkinListCtrl

IMPLEMENT_DYNAMIC(CSkinListCtrl, CListCtrl)

CSkinListCtrl::CSkinListCtrl()
{
	m_nCurSelItem = -1;
	SetRowHeight(30);
}

CSkinListCtrl::~CSkinListCtrl()
{
}


BEGIN_MESSAGE_MAP(CSkinListCtrl, CListCtrl)
	ON_WM_LBUTTONDOWN()
	ON_WM_CREATE()
	ON_WM_MEASUREITEM_REFLECT()
END_MESSAGE_MAP()

// CSkinListCtrl message handlers

void CSkinListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
	ASSERT(pDC != NULL);

	int nColumn = m_HeaderCtrl.GetItemCount();
	for(int i=0; i<nColumn; i++)
	{
		DrawEveryone(pDC, lpDrawItemStruct->itemID, i);
	}
}

int CSkinListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CListCtrl::OnCreate(lpCreateStruct) == -1)
		return -1;

	CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();

	//用我们自己的headctrl去子类化系统的
	if(pHeaderCtrl)
	{
		m_HeaderCtrl.SubclassWindow(pHeaderCtrl->m_hWnd);
	}

	SetBkColor(RGB(174, 183, 193));

	return 1;
}

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

	ModifyStyle(NULL, LVS_OWNERDRAWFIXED);

	CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();

	//用我们自己的headctrl去子类化系统的
	if(pHeaderCtrl)
	{
		m_HeaderCtrl.SubclassWindow(pHeaderCtrl->m_hWnd);
	}

	SetBkColor(RGB(174, 183, 193));
}

void CSkinListCtrl::DrawEveryone(CDC* pDC, int nItem, int nSubItem)
{
	CRect rectItem;
	int   nTextAlign;
	CString strItem;
	int   nItemState;

	nItemState = GetItemState(nItem, nSubItem);
	strItem = GetItemText(nItem, nSubItem);
	nTextAlign = GetTextAlign(nSubItem);
	VERIFY(GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rectItem));

	RectF        rectF(rectItem.left, rectItem.top, rectItem.Width(), rectItem.Height());
	Graphics     graph(pDC->m_hDC);

	//根据选中状态填充背景
	switch(nItemState)
	{
	case ITEM_SELECTED:
		{
			graph.FillRectangle(&SolidBrush(Color(203, 209, 216)), rectF);
			break;
		}
	default:
		{
			graph.FillRectangle(&SolidBrush(Color(174, 183, 193)), rectF);
			break;
		}
	}

	//根据文本排列方向 画文字
	FontFamily fontFamily(L"微软雅黑");
	Gdiplus::Font       font(&fontFamily, 10, FontStyleRegular, UnitPoint);

	SolidBrush solidBrush(Color::Black);
	StringFormat stringFormat;
	stringFormat.SetLineAlignment(StringAlignmentCenter);

	switch(nTextAlign)
	{
	case TEXT_ALIGN_CENTER:
		{
			stringFormat.SetAlignment(StringAlignmentCenter);
			break;
		}
	case TEXT_ALIGN_RIGHT:
		{
			stringFormat.SetAlignment(StringAlignmentFar);
			break;
		}
	default:
		{
			ASSERT(nTextAlign == TEXT_ALIGN_LEFT);
			stringFormat.SetAlignment(StringAlignmentNear);
			rectF.X += 10.0f;  //不要完全靠左 不好看
			break;
		}
	}

	graph.DrawString(strItem, strItem.GetLength(), &font, rectF, &stringFormat, &solidBrush);
}

int CSkinListCtrl::GetTextAlign(int nColumn)
{
	LVCOLUMN col;
	col.mask = LVCF_WIDTH | LVCF_FMT;
	VERIFY(GetColumn(nColumn, &col));

	//获得文字是要居中还是要左右
	if(col.fmt & LVCFMT_LEFT)
		return TEXT_ALIGN_LEFT;
	else if(col.fmt & LVCFMT_CENTER)
		return TEXT_ALIGN_CENTER;
	else if(col.fmt & LVCFMT_RIGHT)
		return TEXT_ALIGN_RIGHT;

	//默认左边
	return TEXT_ALIGN_LEFT;
}

int CSkinListCtrl::GetItemState(int nItem, int nSubItem)
{
	if(nItem == m_nCurSelItem)
		return ITEM_SELECTED;
	else
		return ITEM_UNKNOWN;
	//LVITEM  item;

	//item.mask = LVIF_STATE;
	//item.iItem = nItem;
	//item.iSubItem = nSubItem;

	//VERIFY(GetItem(&item));

	//if(item.state & LVIS_SELECTED)
	//	return ITEM_SELECTED;
	//else if(item.state & LVIS_FOCUSED)
	//	return ITEM_FOCUSED;
	//else
	//	return ITEM_UNKNOWN;
}

void CSkinListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
	UINT uFlags;
	int nItem = HitTest(point, &uFlags);

	if (uFlags & LVHT_ONITEMLABEL)
	{		
		if(m_nCurSelItem != nItem)
		{
			//刷新之前的
			CRect rect;
			GetItemRect(m_nCurSelItem, &rect, LVIR_BOUNDS);
			InvalidateRect(&rect);

			//重置
			m_nCurSelItem = nItem;
		}
	}

	CListCtrl::OnLButtonDown(nFlags, point);
}

void CSkinListCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	if (m_nRowHeight>0)
	{
		lpMeasureItemStruct->itemHeight = m_nRowHeight;
	}
}

void CSkinListCtrl::SetRowHeight(int nHeight)
{
	m_nRowHeight = nHeight;
}


 

你可能感兴趣的:(【MFC】控件自绘之CListCtrl)