CTreeCtrl:实现子结点随父结点状态一致的方法
来源:互联网 发布:手机端淘宝详情页制作 编辑:程序博客网 时间:2024/05/16 17:31
- CTreeCtrl的节点带有checkbox
- 由上到下控件: 将一个节点被check后,其所有的子结点被check; 反之,uncheck,则所有子节点unchecked
- 由下到上控制: 所有子节点被check后,这些节点的父结点被check; 如果子节点由*全被选中*状态,取消掉一个,则父节点应该置为*uncheck*
图片说明:
- void CClassTreeWnd::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: 在此添加控件通知处理程序代码
CPoint pt;
::GetCursorPos(&pt);
UINT uFlags=0;
RECT rect;
GetWindowRect(&rect);
CPoint ptTest;
//作减法是为了?
ptTest.x = pt.x - rect.left ;
ptTest.y = pt.y - rect.top ;
HTREEITEM hItem = HitTest(ptTest,&uFlags);
if (hItem!=NULL)
{
if( uFlags & TVHT_ONITEMSTATEICON )
{
theFirstStartItem = false;
m_bSetCheckOrChecked = GetCheck(hItem);
//遍历,所有子结点都打setcheck
TreeTravesal(hItem);
// 检查父结点是否需要变化
//ChangePrtItemAcdByChild(hItem);
::PostMessage(this->m_hWnd, CHANGE_PARENT_ITEM_CHECK, NULL, NULL);
}
}
*pResult = 0;
} - 父——子
// 遍历一个树的所有子结点,并将其设为选中状态
//by Xue 20.09 2011
void CClassTreeWnd::TreeTravesal(HTREEITEM hStartItem)
{
//得到其子结点
HTREEITEM hChildItem = this->GetChildItem(hStartItem);
//对其子结点进行遍历
while(hChildItem!=NULL)
{
if (m_bSetCheckOrChecked)
{
SetCheck(hChildItem,FALSE);
}
else
{
SetCheck(hChildItem);
}
TreeTravesal(hChildItem); //递归遍历孩子节点
//对其兄弟结点进行遍历
hChildItem =this->GetNextItem(hChildItem, TVGN_NEXT);
}
}
//by Xue 20.09 2011
void CClassTreeWnd::TreeTravesal(HTREEITEM hStartItem)
{
//得到其子结点
HTREEITEM hChildItem = this->GetChildItem(hStartItem);
//对其子结点进行遍历
while(hChildItem!=NULL)
{
if (m_bSetCheckOrChecked)
{
SetCheck(hChildItem,FALSE);
}
else
{
SetCheck(hChildItem);
}
TreeTravesal(hChildItem); //递归遍历孩子节点
//对其兄弟结点进行遍历
hChildItem =this->GetNextItem(hChildItem, TVGN_NEXT);
}
}
子——父
void CClassTreeWnd::ChangePrtItemAcdByChild( HTREEITEM hItemClicked )
{
// 得到父节点
HTREEITEM hParent = GetParentItem(hItemClicked);
if (NULL != hParent)// 如果父节点不为空
{
// 记录父结点的状态
bool bParentIsChecked = true;
// 检查父结点的所有子结点
HTREEITEM hChild = GetNextItem(hParent,TVGN_CHILD);
while(NULL != hChild)
{
if (!GetCheck(hChild))// 有任一结点为 非选中状态,
{ // 则父节点不满足全选条件,置为unchecked
bParentIsChecked = false;
break;// 跳出检查
}
// 下一个子结点
hChild = GetNextSiblingItem(hChild);
}
// 设置父结点的状态
SetCheck(hParent,bParentIsChecked);
// 检查上级节点
ChangePrtItemAcdByChild(hParent);
}
}
{
// 得到父节点
HTREEITEM hParent = GetParentItem(hItemClicked);
if (NULL != hParent)// 如果父节点不为空
{
// 记录父结点的状态
bool bParentIsChecked = true;
// 检查父结点的所有子结点
HTREEITEM hChild = GetNextItem(hParent,TVGN_CHILD);
while(NULL != hChild)
{
if (!GetCheck(hChild))// 有任一结点为 非选中状态,
{ // 则父节点不满足全选条件,置为unchecked
bParentIsChecked = false;
break;// 跳出检查
}
// 下一个子结点
hChild = GetNextSiblingItem(hChild);
}
// 设置父结点的状态
SetCheck(hParent,bParentIsChecked);
// 检查上级节点
ChangePrtItemAcdByChild(hParent);
}
}
关于响应时机的说明
注意到对于“父——子”这种情况,可以直接调用上面的函数;但对“子——父”这种情况,直接调用的话,在单击的时候,结点的“check”或者“uncheck”状态还未发生改变,会判断错误。
比如,一个结点有3个子结点,已经有两个打上了勾,这时点击第三个。正确的响应是父结点也被打上勾,这是因为三个已经满了。
但是实际的情况却是:当三个全部打上勾,再点击取消一个的时候,会把父结点打上勾。这时因为判断的是点击前的状态,而不是点击后的状态。
很自然的想法是,如果MFC有AfterClick()事件的响应函数该多好。可惜没有。
所以需要:
1. 手动定义消息:CHANGE_PARENT_ITEM_CHECK
2. 在OnNMClick()函数里发送消息
3. 消息响应函数里调用上面的第2个函数
- CTreeCtrl:实现子结点随父结点状态一致的方法
- CTreeCtrl 父结点联动子结点CheckBox
- CTreeCtrl 父结点联动子结点CheckBox
- 父结点、子结点、兄弟结点
- MFC CTreeCtrl类的结点遍历查找
- 将ListView的Chekbox状态应用到子结点
- Hibernate实现无限子结点的树形目录
- Hibernate实现无限子结点的树形目录
- 求二叉树叶子结点的递归实现
- 获取CTreeCtrl所有结点的附加数据(ItemData)
- 自己写的一个根据结点名称查找CTreeCtrl树中对应结点的方法(用的是递归思想)
- 自己写的一个根据结点名称查找CTreeCtrl树中对应结点的方法(用的是递归思想)
- 在.Net Framework1.1的环境下,调用TreeView控件,生成树图,点选父节点,则所有的子结点也选中,取消选中的父节点下的子结点,则父节点也取消选中状态。
- c++输出二叉树叶子结点并输出叶子结点到根结点的路径长度
- TreeView的CheckBoxs的第三种状态(有部分子结点被选中)
- 二叉树的结点实现
- 单链表的实现(带头结点)
- 单链表的实现(带头结点)
- Unity3D翻译——Rendering with Replaced Shaders
- Android Activity 笔记 1
- DHCP报文解析
- Qt连接MySQL出现QSqlDatabase: QMYSQL driver not loaded
- ubuntu tab键命令不能补全的问题
- CTreeCtrl:实现子结点随父结点状态一致的方法
- IHTMLDocument2的所有成员、属性、方法、事件
- 做一个老实人 真的很难!
- 算法设计、分析与实现 从入门到精通 C、C++和Java 这本书的堆实现85页C++语言实现有问题
- 镇流器
- Unity3D翻译——Using Depth Textures
- IDCAMS
- CFile最基础读写文件(double为例)
- x&(x-1)含义