打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
MFC,实现三态树形控件以及父子节点联动

首先创建CXPTreeCtrl继承与CTreeCtrl,下面是头文件

class CXPTreeCtrl : public CTreeCtrl{// Constructionpublic:    CXPTreeCtrl();// Attributespublic:    HBITMAP m_hBmpScrollBar ;// Operationspublic:    void SetCheckBoxBitMap(UINT ID)//在主对话框中使用,用于加载checkbox位图    {        m_imgState.Create(ID,13, 1, RGB(255,255,255));        SetImageList(&m_imgState,TVSIL_STATE);    }// Overrides    // ClassWizard generated virtual function overrides    //{{AFX_VIRTUAL(CXPTreeCtrl)    //}}AFX_VIRTUAL// Implementationpublic:    BOOL SetItemState(HTREEITEM hItem, UINT nState, UINT nStateMask, BOOL bSearch=TRUE);    virtual ~CXPTreeCtrl();    // Generated message map functionsprotected:    //{{AFX_MSG(CXPTreeCtrl)    afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult);    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);    //}}AFX_MSG    DECLARE_MESSAGE_MAP()private:    UINT m_uFlags;    void TravelSiblingAndParent(HTREEITEM hItem, int nState);    void TravelChild(HTREEITEM hItem, int nState);    CImageList m_imgState;};

然后是实现文件

// XPTreeCtrl.cpp : implementation file//#include "stdafx.h"#include "XPTreeCtrl.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CXPTreeCtrlCXPTreeCtrl::CXPTreeCtrl(){    m_uFlags=0;}CXPTreeCtrl::~CXPTreeCtrl(){}BEGIN_MESSAGE_MAP(CXPTreeCtrl, CTreeCtrl)    //{{AFX_MSG_MAP(CXPTreeCtrl)    ON_NOTIFY_REFLECT(NM_CLICK, OnClick)    ON_WM_LBUTTONDOWN()    ON_WM_KEYDOWN()    //}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CXPTreeCtrl message handlersvoid CXPTreeCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult) {    if(m_uFlags&TVHT_ONITEMSTATEICON) *pResult=1;    else *pResult = 0;}void CXPTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) {    HTREEITEM hItem =HitTest(point, &m_uFlags);    if (hItem != NULL)    {        SetFocus();        SelectItem(hItem);    }    if ( (m_uFlags&TVHT_ONITEMSTATEICON ))    {        //nState: 0->无选择钮 1->没有选择 2->部分选择 3->全部选择        UINT nState = GetItemState( hItem, TVIS_STATEIMAGEMASK ) >> 12;        nState=(nState==3)?1:3;        SetItemState( hItem, INDEXTOSTATEIMAGEMASK(nState), TVIS_STATEIMAGEMASK );    }    CTreeCtrl::OnLButtonDown(nFlags, point);}void CXPTreeCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {    //处理空格键    if(nChar==0x20)    {        HTREEITEM hItem =GetSelectedItem();        UINT nState = GetItemState( hItem, TVIS_STATEIMAGEMASK ) >> 12;        if(nState!=0)        {            nState=(nState==3)?1:3;            SetItemState( hItem, INDEXTOSTATEIMAGEMASK(nState), TVIS_STATEIMAGEMASK );        }    }    else CTreeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);}BOOL CXPTreeCtrl::SetItemState(HTREEITEM hItem, UINT nState, UINT nStateMask, BOOL bSearch){    BOOL bReturn=CTreeCtrl::SetItemState( hItem, nState, nStateMask );    UINT iState = nState >> 12;    if(iState!=0)    {        if(bSearch) TravelChild(hItem, iState);        TravelSiblingAndParent(hItem,iState);    }    return bReturn;}void CXPTreeCtrl::TravelChild(HTREEITEM hItem, int nState){    HTREEITEM hChildItem,hBrotherItem;    //查找子节点,没有就结束    hChildItem=GetChildItem(hItem);    if(hChildItem!=NULL)    {        //设置子节点的状态与当前节点的状态一致        CTreeCtrl::SetItemState( hChildItem, INDEXTOSTATEIMAGEMASK(nState), TVIS_STATEIMAGEMASK );        //再递归处理子节点的子节点和兄弟节点        TravelChild(hChildItem, nState);        //处理子节点的兄弟节点和其子节点        hBrotherItem=GetNextSiblingItem(hChildItem);        while (hBrotherItem)        {            //设置子节点的兄弟节点状态与当前节点的状态一致            int nState1 = GetItemState( hBrotherItem, TVIS_STATEIMAGEMASK ) >> 12;            if(nState1!=0)            {                CTreeCtrl::SetItemState( hBrotherItem, INDEXTOSTATEIMAGEMASK(nState), TVIS_STATEIMAGEMASK );            }            //再递归处理子节点的兄弟节点的子节点和兄弟节点            TravelChild(hBrotherItem, nState);            hBrotherItem=GetNextSiblingItem(hBrotherItem);        }    }}void CXPTreeCtrl::TravelSiblingAndParent(HTREEITEM hItem, int nState){    HTREEITEM hNextSiblingItem,hPrevSiblingItem,hParentItem;    //查找父节点,没有就结束    hParentItem=GetParentItem(hItem);    if(hParentItem!=NULL)    {        int nState1=nState;//设初始值,防止没有兄弟节点时出错        //查找当前节点下面的兄弟节点的状态        hNextSiblingItem=GetNextSiblingItem(hItem);        while(hNextSiblingItem!=NULL)        {            nState1 = GetItemState( hNextSiblingItem, TVIS_STATEIMAGEMASK ) >> 12;            if(nState1!=nState && nState1!=0) break;            else hNextSiblingItem=GetNextSiblingItem(hNextSiblingItem);        }        if(nState1==nState)        {            //查找当前节点上面的兄弟节点的状态            hPrevSiblingItem=GetPrevSiblingItem(hItem);            while(hPrevSiblingItem!=NULL)            {                nState1 = GetItemState( hPrevSiblingItem, TVIS_STATEIMAGEMASK ) >> 12;                if(nState1!=nState && nState1!=0) break;                else hPrevSiblingItem=GetPrevSiblingItem(hPrevSiblingItem);            }        }        if(nState1==nState || nState1==0)        {            nState1 = GetItemState( hParentItem, TVIS_STATEIMAGEMASK ) >> 12;            if(nState1!=0)            {                //如果状态一致,则父节点的状态与当前节点的状态一致                CTreeCtrl::SetItemState( hParentItem, INDEXTOSTATEIMAGEMASK(nState), TVIS_STATEIMAGEMASK );            }            //再递归处理父节点的兄弟节点和其父节点            TravelSiblingAndParent(hParentItem,nState);        }        else        {            //状态不一致,则当前节点的父节点、父节点的父节点……状态均为第三态            hParentItem=GetParentItem(hItem);            while(hParentItem!=NULL)            {                nState1 = GetItemState( hParentItem, TVIS_STATEIMAGEMASK ) >> 12;                if(nState1!=0)                {                    CTreeCtrl::SetItemState( hParentItem, INDEXTOSTATEIMAGEMASK(2), TVIS_STATEIMAGEMASK );                }                hParentItem=GetParentItem(hParentItem);            }        }    }   }



以上就实现了三态树的所有功能,接下来是使用方法

假设主对话框是CMyDlg,此时已经通过DDX添加了树形控件CTreeCtrl m_treeCtrl
把CTreeCtrl m_treeCtrl 改为 CXPTreeCtrl m_treeCtrl
重载BOOL OnInitDialog();
在其中添加以下代码,主要是加载checkbox的位图

//加载树形控件的资源,假设加载的位图ID是IDB_MultiTreeCheckBoxm_treeCtrl.SetCheckBoxBitMap(IDB_MultiTreeCheckBox);

如果要获取当前checkbox的状态

//其中 nState: 0->无选择钮 1->没有选择 2->部分选择 3->全部选择UINT nState = m_treeCtrl.GetItemState( cItem, TVIS_STATEIMAGEMASK ) >> 12;

设置当前checkbox的状态

//SetItemState()是被重载过的函数,因此这样设置后,父子节点会保持一致//同样 0->无选择钮 1->没有选择 2->部分选择 3->全部选择,数字填在INDEXTOSTATEIMAGEMASK()中m_treeCtrl.SetItemState(item, INDEXTOSTATEIMAGEMASK(3), TVIS_STATEIMAGEMASK );

整体的三态树形控件就是这样创建和使用的。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
CTreeCtrl重载时若干个技巧
VC中三态选择树实现的终结者
VC程序中树型控件节点拖动的完美实现
VC中如何使用CTreeCtrl控件 - 春天的事业 - 草根IT工作者谢春业的博客,探讨...
在CFormView或对话框中动态添加CScrollView、CFormView
vc 控件 自绘
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服