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);
};
MyTreeCtrl.cpp
#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();
}
2、调用方式
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);
}