现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

MFC树控件节点后加图标实现

2012-08-21 05:45 工业·编程 ⁄ 共 4622字 ⁄ 字号 暂无评论

    MFC树控件未提供节点后加图标的方法,需要自己重绘来实现。主要方法是,响应NM_CUSTOMDRAW消息,在每个节点后添加自己要展示的图标。关于NM_CUSTOMDRAW消息的说明,见http://msdn.microsoft.com/en-us/library/ms833744.aspx

显示效果,如下图。

clip_image001

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);
}

给我留言

留言无头像?