【MFC】控件自绘之CTreeCtrl

一:

     树形控件是非常常用的控件之一,可能有些刚学自绘的同学会觉得树形控件的自绘很麻烦。其实不然,请看代码。

 

二:

.h头文件

class CResourceTreeCtrl : public CTreeCtrl
{
	DECLARE_DYNAMIC(CResourceTreeCtrl)

public:
	CResourceTreeCtrl();
	virtual ~CResourceTreeCtrl();

	void SetExpandImage(CImageList* pImageList);

protected:
	DECLARE_MESSAGE_MAP()

	afx_msg void OnPaint();
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnMouseLeave();
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);

protected:

	virtual void PreSubclassWindow();

private:

	int  GetExpandImageIndex(HTREEITEM hItem, CRect& rectExpand);
	
	void ComputeExpandRect(HTREEITEM hItem, CRect& rectExpand);
	void ComputeImageRect(HTREEITEM hItem, CRect& rectImage);

private:

	void DrawTree(CDC* pDC);
	void DrawItem(CDC* pDC, HTREEITEM hItem);
	void DrawExpand(CDC* pDC, HTREEITEM hItem);
	void DrawImage(CDC* pDC, HTREEITEM hItem);
	void DrawText(CDC* pDC, HTREEITEM hItem);
	void DrawBackGnd(CDC* pDC, HTREEITEM hItem);

private:

	BOOL          m_bMouseOut;                            //鼠标是否出去
	HTREEITEM     m_hCurItem;                             //当前选中项
	HTREEITEM     m_hHoverItem;                           //当前悬停项
	CImageList*   m_pExpandImage;
};





cpp源文件

// CResourceTreeCtrl

IMPLEMENT_DYNAMIC(CResourceTreeCtrl, CTreeCtrl)

CResourceTreeCtrl::CResourceTreeCtrl()
{
	m_bMouseOut = TRUE;
	m_hCurItem  = NULL;
	m_hHoverItem = NULL;
}

CResourceTreeCtrl::~CResourceTreeCtrl()
{
}


BEGIN_MESSAGE_MAP(CResourceTreeCtrl, CTreeCtrl)
	ON_WM_MOUSEMOVE()
	ON_WM_MOUSELEAVE()
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()



// CResourceTreeCtrl message handlers

BOOL CResourceTreeCtrl::OnEraseBkgnd(CDC* pDC)
{
	return TRUE;
}

void CResourceTreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
	if(m_bMouseOut)
	{
		TRACKMOUSEEVENT tm;

		tm.cbSize = sizeof(TRACKMOUSEEVENT);
		tm.dwFlags = TME_LEAVE;   
		tm.dwHoverTime = 500;  
		tm.hwndTrack = m_hWnd;

		_TrackMouseEvent(&tm);	
		
		m_bMouseOut = FALSE;
	}

	HTREEITEM hMoveItem = HitTest(point);

	if(hMoveItem != m_hHoverItem)
	{
		m_hHoverItem = hMoveItem;

		Invalidate();
	}

	CTreeCtrl::OnMouseMove(nFlags, point);
}

void CResourceTreeCtrl::OnMouseLeave()
{
	if(!m_bMouseOut)
	{
		m_bMouseOut = TRUE;

		HTREEITEM hItem = m_hHoverItem;
		
		m_hHoverItem =  NULL;

		Invalidate();
	}
}

void CResourceTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
	HTREEITEM hCurItem = HitTest(point);
	
	if(hCurItem)
	{
		SelectItem(hCurItem);

		SetItemState(hCurItem, TVIS_SELECTED, TVIS_SELECTED);

		m_hCurItem = hCurItem;

		Invalidate();
	}

	CTreeCtrl::OnLButtonDown(nFlags, point);
}

void CResourceTreeCtrl::OnPaint()
{
	CPaintDC dc(this);

	CMemDCC  DCMemory(&dc);
	CRect    rect;
	GetClientRect(&rect);

	//////
	DrawTree(&DCMemory);
}

void CResourceTreeCtrl::PreSubclassWindow()
{
	CTreeCtrl::PreSubclassWindow();
}

void CResourceTreeCtrl::DrawTree(CDC* pDC)
{
	/////
	CRect rect;
	COLORREF bkColor;

	CECMSVisualManager::GetInstance()->GetBKColor(bkColor);
	GetClientRect(&rect);

	Graphics graph(pDC->m_hDC);

	graph.FillRectangle(&SolidBrush(Color(255, GetRValue(bkColor), GetGValue(bkColor), GetBValue(bkColor))),\
		RectF(rect.left, rect.top, rect.Width(), rect.Height()));

	/////

	HTREEITEM hItem;

	hItem = GetFirstVisibleItem();

	while(hItem != NULL)
	{
		DrawItem(pDC, hItem);

		hItem = GetNextVisibleItem(hItem);
	}
}

void CResourceTreeCtrl::DrawItem(CDC* pDC, HTREEITEM hItem)
{
	///先画背景,再画展开,图像,文字
	DrawBackGnd(pDC, hItem);
	DrawExpand(pDC, hItem);
	DrawImage(pDC, hItem);
	DrawText(pDC, hItem);
}

void CResourceTreeCtrl::DrawBackGnd(CDC* pDC, HTREEITEM hItem)
{
	Graphics        graph(pDC->m_hDC);

	graph.SetSmoothingMode(SmoothingModeAntiAlias);
	graph.SetInterpolationMode(InterpolationModeHighQualityBicubic);

	CRect           rectItem;

	GetItemRect(hItem, &rectItem, FALSE);

	RectF rectF(rectItem.left, rectItem.top, rectItem.Width(), rectItem.Height());

	////////////////////////选中
	if(m_hCurItem == hItem)
	{
		COLORREF from, to;
		CECMSVisualManager::GetInstance()->GetSelectGradientColor(from, to);
		LinearGradientBrush lineGrBrush(
			rectF,
			Color(255, GetRValue(from), GetGValue(from), GetBValue(from)),//Color(255, 28, 28, 28),
			Color(255, GetRValue(to), GetGValue(to), GetBValue(to)),//Color(255, 172, 172, 172),
			LinearGradientModeHorizontal
			);

		lineGrBrush.SetBlendTriangularShape(0.5f, 1.0f);

		graph.FillRectangle(&lineGrBrush, rectF);

	} //////////////////////悬停
	else if(m_hHoverItem == hItem)
	{	
		/*GraphicsPath      path;

		path.AddRectangle(rectF);

		PathGradientBrush pathGrBrush(&path);

		int nCount = 1;
		pathGrBrush.SetCenterColor(Color(m_nA, m_nR, m_nG, m_nB));
		pathGrBrush.SetSurroundColors(&Color(100, m_nR, m_nG, m_nB), &nCount);

		graph.FillRectangle(&pathGrBrush, rectF);*/
		COLORREF from, to;
		CECMSVisualManager::GetInstance()->GetSelectGradientColor(from, to);
		LinearGradientBrush lineGrBrush(
			rectF,
			Color(100, GetRValue(from), GetGValue(from), GetBValue(from)),//Color(100, 28, 28, 28),
			Color(100, GetRValue(to), GetGValue(to), GetBValue(to)),//Color(100, 172, 172, 172),
			LinearGradientModeHorizontal
			);

		lineGrBrush.SetBlendTriangularShape(0.5f, 1.0f);
		lineGrBrush.SetGammaCorrection(TRUE);

		graph.FillRectangle(&lineGrBrush, rectF);
	}
}

void CResourceTreeCtrl::DrawExpand(CDC* pDC, HTREEITEM hItem)
{
	BOOL        bHasChild   = ItemHasChildren(hItem);

	if(bHasChild && m_pExpandImage->GetSafeHandle())
	{	
		int nImage;

		CRect rectExpand;

		ComputeExpandRect(hItem, rectExpand);

		nImage = GetExpandImageIndex(hItem, rectExpand);

		m_pExpandImage->Draw(pDC, nImage, rectExpand.TopLeft(), ILD_TRANSPARENT);
		
	}
}

void CResourceTreeCtrl::DrawImage(CDC* pDC, HTREEITEM hItem)
{
	CImageList*  pItemImage  = GetImageList(TVSIL_NORMAL);
	CImageList*  pStateImage = GetImageList(TVSIL_STATE);
	DWORD        itemState   = GetItemState(hItem, TVIF_STATE);

	int nImage, nSelectImage;

	VERIFY(GetItemImage(hItem, nImage, nSelectImage));

	CImageList*       pNormalImage = GetImageList(TVSIL_NORMAL);
	
	if(pNormalImage)
	{
		CRect       rectImage;

		ComputeImageRect(hItem, rectImage);

		pNormalImage->Draw(pDC, nImage, rectImage.TopLeft(), ILD_TRANSPARENT);
	}
}

void CResourceTreeCtrl::DrawText(CDC* pDC, HTREEITEM hItem)
{
	CString     strItemText = GetItemText(hItem);
	CRect       rectText;

	GetItemRect(hItem, &rectText, TRUE);

	RectF       rectF(rectText.left, rectText.top, rectText.Width(), rectText.Height());

	Graphics    graph(pDC->m_hDC);
	CFont*      pFont = GetFont();
	LOGFONT     LogFont;

	if(pFont)
	{
		pFont->GetLogFont(&LogFont);
	}
	else
	{
		ZeroMemory(&LogFont, sizeof(LOGFONT));
		lstrcpy(LogFont.lfFaceName, _T("微软雅黑"));
	}

	Gdiplus::Font       font(LogFont.lfFaceName, 10, FontStyleRegular, UnitPoint);
	Gdiplus::StringFormat stringFormat;
	stringFormat.SetAlignment(StringAlignmentNear);
	stringFormat.SetLineAlignment(StringAlignmentCenter);
	stringFormat.SetFormatFlags(StringFormatFlagsLineLimit );

	RectF               boundBox;

	graph.MeasureString(strItemText, strItemText.GetLength(), &font, PointF(0, 0), &stringFormat, &boundBox);

	rectF.X = rectText.left;
	rectF.Y = rectText.top;
	rectF.Width = boundBox.Width;
	rectF.Height = boundBox.Height;

	COLORREF texColor;
	CECMSVisualManager::GetInstance()->GetTextColor(texColor);

	graph.DrawString(strItemText, strItemText.GetLength(), &font, rectF, 
		&stringFormat, &SolidBrush(Color(255, GetRValue(texColor), GetGValue(texColor), GetBValue(texColor))));
}

void CResourceTreeCtrl::ComputeExpandRect(HTREEITEM hItem, CRect& rectExpand)
{
	ASSERT(m_pExpandImage->GetSafeHandle());

	CRect        rectText;
	CRect        rectItem;
	CRect        rectImage;

	GetItemRect(hItem, &rectText, TRUE);
	GetItemRect(hItem, &rectItem, FALSE);

	ComputeImageRect(hItem, rectImage);

	rectExpand = rectImage;

	IMAGEINFO   imageInfo = {0};
	int         nCount    = 0;

	m_pExpandImage->GetImageInfo(0, &imageInfo);
	nCount = m_pExpandImage->GetImageCount();

	int nExpandImageWidth = CRect(imageInfo.rcImage).Width();
	int nExpandImageHeight = CRect(imageInfo.rcImage).Height();

	rectExpand.left -= 3;
	rectExpand.left -= nExpandImageWidth;
	rectExpand.top  = rectItem.top + (rectItem.Height() - nExpandImageHeight)/2;
	rectExpand.bottom = rectExpand.top + nExpandImageHeight;
	rectExpand.right = rectExpand.left + nExpandImageWidth;
}

void CResourceTreeCtrl::ComputeImageRect(HTREEITEM hItem, CRect& rectImage)
{
	CRect        rectText;
	CRect        rectItem;

	GetItemRect(hItem, &rectText, TRUE);
	GetItemRect(hItem, &rectItem, FALSE);

	CImageList*   pNormalImage = GetImageList(TVSIL_NORMAL);
	//	CImageList*   pStateImage = GetImageList(TVSIL_STATE);

	rectImage = rectText;
	rectImage.left -= 3;

	if(pNormalImage)
	{
		int nImage = 0;
		int nSelectedImage = 0;

		if(GetItemImage(hItem, nImage, nSelectedImage))
		{
			IMAGEINFO   imageInfo = {0};
			int         nCount    = 0;

			pNormalImage->GetImageInfo(0, &imageInfo);
			nCount = pNormalImage->GetImageCount();

			int nItemImageWidth = CRect(imageInfo.rcImage).Width();
			int nItemImageHeight = CRect(imageInfo.rcImage).Height();

			rectImage.left -= nItemImageWidth;
			rectImage.right = rectImage.left + nItemImageWidth;
		}
	}
}

int CResourceTreeCtrl::GetExpandImageIndex(HTREEITEM hItem, CRect& rectExpand)
{
	int          nImage = 0;
	CPoint       ptCursor;

	GetCursorPos(&ptCursor);
	ScreenToClient(&ptCursor);

	DWORD dwState = GetItemState(hItem, TVIF_STATE);

	if(rectExpand.PtInRect(ptCursor))
	{
		if(dwState & TVIS_EXPANDED)
		{
			nImage = 2;
		}
		else
		{
			nImage = 1;
		}
	}
	else
	{
		if(dwState & TVIS_EXPANDED)
		{
			nImage = 3;
		}
		else
		{
			nImage = 0;
		}
	}

	return nImage;
}

void CResourceTreeCtrl::SetExpandImage(CImageList* pImageList)
{
	ASSERT(pImageList != NULL);

	m_pExpandImage = pImageList;
}


 

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