最近做课程设计是用到了树形控件,原来对树形控件的用法基本都忘了,这次又重新整合了一下,以加深记忆。
树形控件可以用于树形的结构,其中有一个根接点(Root)然后下面有许多子结点,而每个子结点上有允许有一个或多个或没有子结点。CTreeCtrl类封装了树形控件的各种操作。在树形控件中每一个结点都有一个HTREEITEM句柄,这个句柄按我的理解其实就是一些十六进制的数,就是用来标识的ID。但是我们通常添加到树形结构的结点都是一些图标或者字符串,这时可以调用:
CString CTreeCtrl::GetItemText(HTREEITEM hItem);
来获得句柄为hItem的显示字符。同理:
BOOL CTreeCtrl::SetItemText( HTREEITEM hItem, LPCTSTR lpszItem );
来将句柄为hItem的显示字符设置为lpszItem 。
一般我们创建了一个树形控件之后就要对这个控件添加结点,CTreeCtrl类提供了一个函数:
HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );
来帮助我们,这个函数的返回值是新添加结点的HTREEITEM句柄,函数的参数lpszItem是要添加结点的显示字符,hParent代表父结点的句柄,默认为根节点,当前添加的结点会排在hInsertAfter表示的结点的后面,默认是添加在最后。利用这个方法我们可以递归添加无穷的结点。下面的代码会建立一个如下形式的树形结构:
+--- Parent1
+--- Child1_1
+--- Child1_2
+--- Child1_3
+--- Parent2
+--- Parent3
/*假设m_tree为一个CTreeCtrl对象,而且该窗口已经创建*/
HTREEITEM hItem,hSubItem;
hItem = m_tree.InsertItem("Parent1",TVI_ROOT);在根结点上添加Parent1
hSubItem = m_tree.InsertItem("Child1_1",hItem);//在Parent1上添加一个子结点
hSubItem = m_tree.InsertItem("Child1_2",hItem,hSubItem);//在Parent1上添加一个子结点,排在Child1_1后面
hSubItem = m_tree.InsertItem("Child1_3",hItem,hSubItem);
hItem = m_tree.InsertItem("Parent2",TVI_ROOT,hItem);
hItem = m_tree.InsertItem("Parent3",TVI_ROOT,hItem);
此外如果想遍历树可以使用下面的函数:
HTREEITEM GetRootItem( );得到根结点。
HTREEITEM GetChildItem( HTREEITEM hItem );得到子结点。
HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明结点的上/下一个兄弟结点。
HTREEITEM GetParentItem( HTREEITEM hItem );得到父结点。
我的程序中利用了这些函数添加了一个三层结构的树,其中考虑了一些结点重复(重复的结点不添加)的问题,发现CTreeCtrl中并没有合适的函数可以使用,于是就自己写了一个,代码如下:
BOOL IsTreeSubItemExist(CTreeCtrl* pTree,HTREEITEM hParent,CString szCurrent)
{
HTREEITEM hChild=pTree->GetChildItem(hParent); //得到子结点
while(hChild!=NULL) //遍历子结点
{
if(pTree->GetItemText(hChild)==szCurrent)
break;
hChild=pTree->GetNextSiblingItem(hChild);
}
if(hChild==NULL)
return FALSE;
else
return TRUE;
}
这个函数用来确定pTree中句柄为hParent的结点是否存在显示字符为szCurrent的结点,若存在返回真,不存在返回假。
在这个函数的基础上,我又写了一个添加的完整的代码,如下:
void CMyView::UpdateTreeViewCtrl()
{
CTreeCtrl* pMyTree=(CTreeCtrl*)this->GetDlgItem(IDC_TREE_MAINALLMSG);
HTREEITEM hItem;
HTREEITEM hSubItem;
CElectricDevice* pNextDevice=m_pFirst->m_nextDevice;
while(pNextDevice!=NULL)
{
if(!IsTreeSubItemExist(pMyTree,TVI_ROOT,pNextDevice->m_brand))
{
hItem=pMyTree->InsertItem(pNextDevice->m_brand,TVI_ROOT);
hSubItem=pMyTree->InsertItem(pNextDevice->m_style,hItem);
pMyTree->InsertItem(pNextDevice->m_type,hSubItem);
}
pNextDevice=pNextDevice->m_nextDevice;
}
pNextDevice=m_pFirst->m_nextDevice;
while(pNextDevice!=NULL)
{
hItem=pMyTree->GetChildItem(TVI_ROOT);
while(hItem!=NULL)
{
if(pMyTree->GetItemText(hItem)==pNextDevice->m_brand)
break;
hItem=pMyTree->GetNextSiblingItem(hItem);
}
if(hItem!=NULL)
{
if(!IsTreeSubItemExist(pMyTree,hItem,pNextDevice->m_style))
{
hSubItem=pMyTree->InsertItem(pNextDevice->m_style,hItem);
pMyTree->InsertItem(pNextDevice->m_type,hSubItem);
}
}
pNextDevice=pNextDevice->m_nextDevice;
}
pNextDevice=m_pFirst->m_nextDevice;
while(pNextDevice!=NULL)
{
hItem=pMyTree->GetChildItem(TVI_ROOT);
while(hItem!=NULL)
{
HTREEITEM hSubSubItem=pMyTree->GetChildItem(hItem);
while(hSubSubItem!=NULL)
{
if(pMyTree->GetItemText(hItem)==pNextDevice->m_brand && pMyTree->GetItemText(hSubSubItem)==pNextDevice->m_style)
{
if(!IsTreeSubItemExist(pMyTree,hSubSubItem,pNextDevice->m_type))
{
pMyTree->InsertItem(pNextDevice->m_type,hSubSubItem);
}
}
hSubSubItem=pMyTree->GetNextSiblingItem(hSubSubItem);
}
hItem=pMyTree->GetNextSiblingItem(hItem);
}
pNextDevice=pNextDevice->m_nextDevice;
}
}
这个函数基本上实现我的目标,但是我觉得在算法上不是很有效率,由于代码很简单我也不介绍了,等有了改进的方法我会再来更新的。
CTreeCtrl还有很多其他的丰富的方法目前此次也没有用到,就只介绍我用到的这些吧!以后用到之后再来补上!