• 网络学院
  • IT资讯
  • 操作系统
  • 网络技术
  • 软件应用
  • 办公软件
  • 编程技术
  • 网站架设
  • 数据库类
  • 平面设计
  • 多媒体类
  • 游戏资讯
  • 教学论文
  • 认证考试
VC中三态选择树实现的终结者
  站点:
  • 首 页
  • 最新软件
  • 文章教程
  • 国内软件
  • 国外软件
  • 绿色软件
  • 源码下载
  • 字体下载
VC中三态选择树实现的终结者
软件发布 VC中三态选择树实现的终结者
网络软件 系统工具 应用软件 联络聊天 图形图像 多媒体类 行业软件 游戏娱乐 编程开发 安全相关 教育教学 数码软件 绿软下载
热门软件: QQ 瑞星 pplive e话通 木马克星 千千静听 office2000 五笔字根 Photoshop 视频分割
返回文章教程首页 >> 文章首页 >> 编程技术 >> VC教程 >> VC中三态选择树实现的终结者

VC中三态选择树实现的终结者

添加时间: 2006-2-12 3:33:54  作者: VC教程  阅读次数:365   来源: http://d9soft.com

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

  
效果图


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

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

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

 

上下文章:

 

上一篇文章: VC中教你如何实现多语言菜单 下一篇文章: VC中设计在窗体中加入3D Bar

相关文章:

  • 飞速在线看视频 傲盾加速帮你实现速度感受
  • 用端口碰撞技术实现服务器远程管理
  • servlet实现oracle中读出文件并显示
  • 在Oracle中实现数据库的复制
  • 在T-SQL中实现Oracle的MINUS集合运算符

相关软件:

  • Windows系统服务终结者 V3.3 绿色版
  • 网页特效终结者 V2.0 Build 2003.05.15
  • Michael4u网页特效终结者 V2.0
  • FF之密码终结者(FFenc) 2.0.0
  • 密码终结者 2005
  • P2P终结者-破解补丁 V2.04

 

快速导航

  • 网络学院
  • 精品汇聚
  • 字体下载
  • 教程下载
  • ASP源码
  • PHP源码
  • Net源码
  • JSP 源码

编程技术分类导航

  • ASP & ASP.NET教程
  • PHP教程
  • JSP教程
  • C/C++教程
  • VB & VB.NET教程
  • VC教程
  • Delphi教程
  • BCB教程
  • VFP教程
  • PB教程
  • JAVA教程
  • XML教程
  • C#教程
  • CGI教程

本类经典文章推荐

  • VC++之Button控件
  • VC++之Static Box控件
  • VC++之Edit Box控件
  • VC++之Static Box控件
  • VC++之Edit Box控件
  • VC++之Scroll Bar
  • VC++之Scroll Bar
  • VC++之List Box/Check List Box控...
  • VC++ Combo Box/Combo Box Ex控件
  • VC++ List Ctrl控件

VC教程阅读排行

  • VC++之List Box/Check List Box控...
  • VC++ List Ctrl控件
  • VC++ Combo Box/Combo Box Ex控件
  • VC++之Button控件
  • VC++之Tab Ctrl控件
  • VC++之Edit Box控件
  • VC++之Edit Box控件
  • VC遍历整个目录树查找文件
  • VC++之Scroll Bar
  • 深入编程:控制面板知多少?

编程技术阅读总排行

  • VB入门教程之一
  • Java连接数据库实例
  • 第二章 PowerBuilder 入门之创建新...
  • VC++之List Box/Check List Box控...
  • 第一章 什么是PowerBuilder
  • VC++ List Ctrl控件
  • VC++ Combo Box/Combo Box Ex控件
  • 学C++不得不看的一篇文章
  • VB入门教程之二
  • VC++之Button控件

广告位置

字母检索 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 回到顶部

关于我们 | 版权声明 | 免责条款 | 广告联系 | 软件发布 | 下载帮助 | 下载排行 | 网站地图 | 特别鸣谢 | 友情连接

copyright; 2005-2008 D9soft.com 第九软件网 版权所有