`
huobengluantiao8
  • 浏览: 1032521 次
文章分类
社区版块
存档分类
最新评论

三态选择树实现终结者

 
阅读更多

三态选择树实现终结者

作者:yuwei 转自-王佳豪出处: 2005-11-4 9:33:00阅读1132



下载本文示例源代码

示例代码运行效果图如下:



在很多情况下,我们经常需要实现树的多态选择,如上图所示,当全部子节点选中的情况下,当前节点才被选中(如图示[荆门市]节点),当子节点部分选中时,当前节点处于第三态(如图示[湖北省]节点)当全部子节点未选中时,当前节点处于未选中的状态(如图示[江苏省]节点)。本文就介绍这种三态选择树的具体实现方法。

在VC知识库第十九期中河南科技大学丛雷朋友也介绍了一种实现方法,两种方法比较,本文介绍的方法实现简单,兼容原CTreeCtrl的全部操作,CheckBox也是采用控件本身的CheckBox,只是在状态显示时重画而已。因此,本方法可以实现表示三态的情况下同时显示节点ICON图标,另增加了对CheckBox在某些节点是否显示的控制,同时增加了对键盘空格键选中、取消选中的控制。具体遍历父、子节点的方法同丛雷朋友朋友的方法类似,也是递归实现全部节点的遍历,只是优化了一些,效率更高。

下面介绍具体使用方法:

步骤一:生成一个对话框工程(示例工程CMutiTree)。

步骤二:添加树控件,按照实际需要设置所需的属性。

步骤三:做节点图标和三态选择框图标



一般情况下节点图标采用16×16,三态选择图标采用13×13大小比较合适。

三态选择图标对应: 0->无选择钮 1->没有选择 2->部分选择 3->全部选择

步骤四:将两个文件[MutiTreeCtrl.cpp ,MutiTreeCtrl.h]添加到步骤一创建的对话框

工程中,在CMutiTreeDlg类的头文件中增加对[MutiTreeCtrl.h]的包含,此时工程中增加了CMutiTreeCtrl类。


#include "MutiTreeCtrl.h"

步骤五:用ClassWizard在CmutiTreeDlg中创建一个树控件CTreeCtrl的对象m_TripleTree,更改该对象为上面步骤四加入的CMutiTreeCtrl类的对象。

步骤六:在CMutiTreeDlg类中定义两个CImageList 类的对象,用于加载CMutiTreeCtrl所需要的节点图标列表和三态选择框图标列表。

在CMutiTreeDlg类的头文件中:
CImageList m_imgList;
CImageList m_imgState;

在对话框的初始化函数中:m_imgState.Create(IDB_BITMAP_STATE,13, 1, RGB(255,255,255));
m_imgList.Create(IDB_BITMAP_LIST,16, 1, RGB(255,255,255));

m_TripleTree.SetImageList(&m_imgList,TVSIL_NORMAL);
m_TripleTree.SetImageList(&m_imgState,TVSIL_STATE);

完成以上六步操作后,编译、运行,用键盘空格键或鼠标单击CheckBox改变其状态,您将看到不需要再增加任何代码,已经实现了三态选择树的功能。如果需要隐藏某些选择框,如根节点的选择框,只需要设置对应的节点状态为0即可: m_TripleTree.SetItemState( hRoot, INDEXTOSTATEIMAGEMASK(0),
TVIS_STATEIMAGEMASK );

上述代码将设置根节点不显示三态选择框。

我具体实现的思想是以Windows标准的CTreeCtrl类为基类派生一个类CMutiTreeCtrl,截获键盘和鼠标点击CheckBox的事件,在此消息响应函数中,更改CheckBox的状态,并搜索子节点、兄弟节点和父节点,更改其状态与上述逻辑一致。方法如下介绍:

一、 CTreeCtrl类为基类派生CMutiTreeCtrl类

class CMutiTreeCtrl : public CTreeCtrl
{
// Construction
public:
CMutiTreeCtrl();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMutiTreeCtrl)
//}}AFX_VIRTUAL
// Implementation

public:
BOOL SetItemState( HTREEITEM hItem, UINT nState, UINT nStateMask, BOOL bSearch=TRUE);
virtual ~CMutiTreeCtrl();
// Generated message map functions
protected:
//{{AFX_MSG(CMutiTreeCtrl)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnStateIconClick(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnKeydown(NMHDR* pNMHDR, LRESULT* pResult);
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);
};

二、重载CTreeCtrl的SetItemState()函数

在调用了基类的SetItemState()函数修改了节点状态以后,遍历一遍当前节点子节点、兄弟节点、父节点,按照上述逻辑修改为相应的状态,实现三态显示。调用此函数有二种情况:

①键盘或鼠标输入修改节点状态,此时要遍历全部父、兄、子节点;

②程序根据实际情况调用修改节点状态,因为修改节点状态时是判断了全部子节点的状态后得出了状态,所以此时仅需要遍历全部的兄、父节点,更改其状态符合逻辑。故在重载的函数后面加了一个缺省为TRUE的bSearch变量,当程序修改节点时请置此标志为FALSE。

BOOL CMutiTreeCtrl::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;
}

三、检测鼠标单击节点CHeckBox的事件,更改对应的节点状态并遍历树的其他节点。

void CMutiTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
HTREEITEM hItem =HitTest(point, &m_uFlags);
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 CMutiTreeCtrl::OnStateIconClick(NMHDR* pNMHDR, LRESULT* pResult)
{
if(m_uFlags&TVHT_ONITEMSTATEICON) *pResult=1;
else *pResult = 0;
}


四、检测键盘按空格键的事件,更改对应的节点状态并遍历树的其他节点。

void CMutiTreeCtrl::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);
}


五、树的遍历用递归的方法搜索当前节点的父、兄、子节点

①递归搜索子节点

void CMutiTreeCtrl::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 CMutiTreeCtrl::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);
}
}
}
}

好了,一切就是这么简单,如果你还不清楚的话,那就打开工程看看吧,如你有什么问题也不要忘记来信告诉我哦!最后祝大家学习愉快,多多交流,多多进步,一切顺利!


http://www.evget.com/zh-CN/Info/catalog/6208.html


分享到:
评论

相关推荐

    商业编程-源码-三态选择树实现终结者.zip

    商业编程-源码-三态选择树实现终结者.zip

    MutiTree_Vc_

    三态选择树实现终结者VC源代码效果不错。

    p2p 终结者 网管

    p2p 终结者 p2p 终结者p2p 终结者 p2p 终结者 p2p 终结者 p2p 终结者p2p 终结者 p2p 终结者 p2p 终结者p2p 终结者 p2p 终结者 p2p 终结者 p2p 终结者p2p 终结者p2p 终结者 p2p 终结者p2p 终结者 p2p 终结者 p2p 终结...

    网吧终结者网吧终结者网吧终结者

    网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者网吧终结者

    P2P终结者 4.04P2P终结者 4.04P2P终结者 4.04

    P2P终结者 4.04P2P终结者 4.04P2P终结者 4.04P2P终结者 4.04P2P终结者 4.04P2P终结者 4.04

    灰色按钮终结者 灰色按钮终结者

    灰色按钮终结者 灰色按钮终结者 灰色按钮终结者 灰色按钮终结者 灰色按钮终结者 灰色按钮终结者 灰色按钮终结者

    用java实现的仿p2p终结者软件

    java版仿p2p终结者,使用arp欺骗实现,另附源码在jar文件中

    驱动防火墙终结者 驱动防火墙终结者

    驱动防火墙终结者 驱动驱动防火墙终结者 防火墙终结者 驱动防火墙终结者 驱动防火墙终结者

    易游还原终结者易游还原终结者易游还原终结者

    易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游还原终结者易游...

    图标终结者ICO

    图标终结者

    p2p终结者4.03

    P2P终结者是由Net.Soft工作室开发的一套专门用来控制企业网络P2P...而且,P2P终结者开发人员将不断跟踪最新P2P协议发展动态,以实现软件更完善的控制功能,同时也会吸取用户的反馈意见,以把P2P终结者软件做得更加完善

    p2p终结者4.34

    P2P终结者基于底层协议分析处理实现,具有很好的透明性。软件可以适应绝大多数网络环境,包括代理服务器、ADSL路由器共享上网,Lan专线等网络接入环境。它可以让您轻松地、傻瓜化地管理局域网中BT、电驴等大量占用...

    终结者木马专杀工具 终结者木马专杀工具

    终结者木马专杀工具 终结者木马专杀工具 终结者木马专杀工具终结者木马专杀工具终结者木马专杀工具 终结者木马专杀工具

    p2pover 终结者

    p2pover 终结者p2pover 终结者p2pover 终结者

    P2P终结者 4.14 

    而且,P2P终结者开发人员将不断跟踪最新P2P协议发展动态,以实现软件更完善的控制功能,同时也会吸取用户的反馈意见,以把P2P终结者软件做得更加完善。 4.03 [2009-01-18] +增加主机配置备份功能 +增加主机配置...

    P2P终结者 4.13

    P2P终结者是一款网络管理软件,用来管理局域网中BT、电驴等大量...而且,P2P终结者开发人员将不断跟踪最新P2P协议发展动态,以实现软件更完善的控制功能,同时也会吸取用户的反馈意见,以把P2P终结者软件做得更加完善。

    P2P终结者+反P2P终结者

    P2P终结者+反P2P终结者 网络管理的好工具

    p2p终结者p2p终结者p2p终结者p2p终结者p2p终结者p2p终结者

    p2p终结者p2p终结者 p2p终结者 p2p终结者 p2p终结者 p2p终结者 p2p终结者 p2p终结者 p2p终结者

    终结者CMCC扫号器

    终结者CMCC扫号器

    反p2p终结者 反p2p终结者破解版

    反p2p终结者 反p2p终结者破解版,实用!!!!!!!!

Global site tag (gtag.js) - Google Analytics