MFC树控件未提供节点后加图标的方法,需要自己重绘来实现。
主要方法是,响应NM_CUSTOMDRAW消息,在每个节点后添加自己要展示的图标。
关于NM_CUSTOMDRAW消息的说明,见http://msdn.microsoft.com/en-us/library/ms833744.aspx。
显示效果,如下图。
1、实现源码
重绘树控件类CMyTreeCtrl。
MyTreeCtrl.h
#pragma once //节点信息 struct NodeInfo { NodeInfo() : strName(_T("")) , nType(0) , bImage(false) { } CString strName;//节点名称 int nType;//节点类型 bool bImage;//是否有图标 }; class CMyTreeCtrl : public CTreeCtrl { public: CMyTreeCtrl(void); virtual ~CMyTreeCtrl(void); protected: //{{AFX_MSG(CMutiTreeCtrl) DECLARE_MESSAGE_MAP() afx_msg void OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult); //}}AFX_MSG private: //为每个条目添加图标 void DrawItemImage(CDC* pOrigDC, CRect origRect); };
#include "StdAfx.h" #include "MyTreeCtrl.h" #include "resource.h" BEGIN_MESSAGE_MAP(CMyTreeCtrl, CTreeCtrl) //{{AFX_MSG_MAP(CMyTreeCtrl) ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw ) //}}AFX_MSG_MAP END_MESSAGE_MAP() CMyTreeCtrl::CMyTreeCtrl(void) { } CMyTreeCtrl::~CMyTreeCtrl(void) { } void CMyTreeCtrl::OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult) { NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR); if (NULL == pLVCD) { return; } *pResult = CDRF_DODEFAULT; *pResult |= CDRF_NOTIFYITEMDRAW; *pResult |= CDRF_NOTIFYSUBITEMDRAW; *pResult |= CDRF_NOTIFYPOSTPAINT; const DWORD dwDrawStage = pLVCD->nmcd.dwDrawStage; if (dwDrawStage != CDDS_ITEMPOSTPAINT) { return; } //界面重绘,树节点后添加图标 HTREEITEM hItem = (HTREEITEM)pLVCD->nmcd.dwItemSpec; NodeInfo* pNodeInfo = (NodeInfo*)GetItemData(hItem); if (NULL == pNodeInfo) { return; } //顶级节点直接返回 if (1 == pNodeInfo->nType) { return; } //不显示图标,直接返回 if (!pNodeInfo->bImage) { return; } CRect textRect; GetItemRect(hItem, &textRect, TRUE); CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); DrawItemImage(pDC, textRect); } void CMyTreeCtrl::DrawItemImage(CDC* pOrigDC, CRect origRect) { //画图采用双缓冲 CDC memDC; memDC.CreateCompatibleDC(pOrigDC); //加载.bmp格式图片 CBitmap bitmap; bitmap.LoadBitmap(IDB_BMP_APPLE); //选择图片对象 memDC.SelectObject(&bitmap); //位图长宽获取 BITMAP bmInfo; bitmap.GetObject(sizeof(BITMAP), &bmInfo); //输出图片 pOrigDC->BitBlt(origRect.right,origRect.top,bmInfo.bmWidth,bmInfo.bmHeight,&memDC,0,0,SRCCOPY); //绘图完成后的清理 bitmap.DeleteObject(); memDC.DeleteDC(); }
vs2005创建基于对话框的MFC程序。
添加树控件,树控件属性设置如下。
ID | IDC_TREE_MY |
Always Show Selection | True |
Check Boxes | True |
Has Buttons | True |
Has Lines | True |
Lines At Root | True |
Tooltips | False |
树控件关联变量m_TreeCtrl,初始化时调用BuildTree方法来生成树。
class CMyTreeTestDlg : public CDialog { public: ...... private: //生成树内容 void BuildTree(); private: CMyTreeCtrl m_TreeCtrl; vector<NodeInfo*> m_vNodeVct; } void CMyTreeTestDlg::BuildTree() { NodeInfo* pTop = new NodeInfo(); //对象放入列表,用于释放内存 m_vNodeVct.push_back(pTop); pTop->strName = _T("顶级节点"); pTop->nType = 1; TV_INSERTSTRUCT tvTreeItem; tvTreeItem.hInsertAfter = TVI_LAST; tvTreeItem.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE; tvTreeItem.hParent = TVI_ROOT; tvTreeItem.item.pszText = const_cast<TCHAR*>((const TCHAR*)(pTop->strName)); tvTreeItem.item.lParam = (LPARAM)(pTop); HTREEITEM hTopItem = m_TreeCtrl.InsertItem(&tvTreeItem); for (int i = 0; i < 10; i++) { static bool bFirstImage = true; NodeInfo* pFirstSub = new NodeInfo(); m_vNodeVct.push_back(pFirstSub); pFirstSub->strName.Format(_T("一级节点%d"), i); pFirstSub->nType = 2; if (bFirstImage) { pFirstSub->bImage = bFirstImage; } bFirstImage = !bFirstImage; TV_INSERTSTRUCT tvFirstSub; tvFirstSub.hInsertAfter = TVI_LAST; tvFirstSub.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE; tvFirstSub.hParent = hTopItem; tvFirstSub.item.pszText = const_cast<TCHAR*>((const TCHAR*)(pFirstSub->strName)); tvFirstSub.item.lParam = (LPARAM)(pFirstSub); HTREEITEM hFirstItem = m_TreeCtrl.InsertItem(&tvFirstSub); for (int j = 0; j < 10; j++) { NodeInfo* pSecSub = new NodeInfo(); m_vNodeVct.push_back(pSecSub); pSecSub->strName.Format(_T("二级节点%d"), j); pSecSub->nType = 3; static bool bSecImage = false; if (bSecImage) { pSecSub->bImage = bSecImage; } bSecImage = !bSecImage; TV_INSERTSTRUCT tvSecSub; tvSecSub.hInsertAfter = TVI_LAST; tvSecSub.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE; tvSecSub.hParent = hFirstItem; tvSecSub.item.pszText = const_cast<TCHAR*>((const TCHAR*)(pSecSub->strName)); tvSecSub.item.lParam = (LPARAM)(pSecSub); HTREEITEM hSecItem = m_TreeCtrl.InsertItem(&tvSecSub); } } //展开顶级节点 m_TreeCtrl.Expand(hTopItem, TVE_EXPAND); }