一:
树形控件是非常常用的控件之一,可能有些刚学自绘的同学会觉得树形控件的自绘很麻烦。其实不然,请看代码。
二:
.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; }