树状控件CTreeCtrl主要用于树状结构的功能使用,其中树状结构有一个根接点(Root),一个根接点下可以有多个子接点或者不设置子接点,子接点也可以作为父节点,使其下也包含若干的子接点,总是可以根据接点之间的上下级关系然后设置相应的接点。
MTreeCtrl::InsertItem 函数为为控件添加接点,其结构如下:
HTREEITEM InsertItem(
LPTVINSERTSRUCT lpInsertStruct
);
HTREEITEM InsertItem(
LPCTSTR lpszItem,
HTREEITEM hParent = TVI_ROOT,
HTREEITEM hInsertAfer = TVI_LAST
);
当需要添加一个接点的时候,做如下操作:
HTREEITEM hTreeItem;
CTreeCtrl m_treeCtrl;
HTREEITEM hTreeSub;
hTreeItem = m_treeCtrl.InsertItem("Root");或者hTreeItem = m_treeCtrl.InsertItem("Root",TVI_Root);
如上操作就相当于给一个树状结构添加了一个根接点。如果还想给该根接点添加一个子接点的话,则如下操作:
hTreeItem = m_treeCtrl.InsertItem("Child",hTreeItem);
MTreeCtrl::InsertItem 函数为为控件添加接点,其结构如下:
HTREEITEM InsertItem(
LPTVINSERTSRUCT lpInsertStruct
);
HTREEITEM InsertItem(
LPCTSTR lpszItem,
HTREEITEM hParent = TVI_ROOT,
HTREEITEM hInsertAfer = TVI_LAST
);
当需要添加一个接点的时候,做如下操作:
HTREEITEM hTreeItem;
CTreeCtrl m_treeCtrl;
HTREEITEM hTreeSub;
hTreeItem = m_treeCtrl.InsertItem("Root");或者hTreeItem = m_treeCtrl.InsertItem("Root",TVI_Root);
如上操作就相当于给一个树状结构添加了一个根接点。如果还想给该根接点添加一个子接点的话,则如下操作:
hTreeItem = m_treeCtrl.InsertItem("Child",hTreeItem);
如上,这样子就创建了一个Root的子接点Child,函数InsertItem中的hTreeItem则为其父接点的句柄。
由此可以推理下去,一个树结构根接点只有一个,然后要创建子接点时,只需记住父接点的句柄,便可以获取相应的子接点,
并且在创建多个子接点的时候,可以直接模仿上面的操作,创建的新的接点直接添加到上面的接点后面。
下面贴下自己实现的代码,主要是将一些数据存到文件中,然后读取出来进行设置树结构。
FileName.txt内容:
Name:Tom,Jony,Gray
City:China,Enlish,Japanese
Data:We,Fri,Sun
initTreeCtrl()函数
void initTreeCtrl()
{
HTREEITEM hTreeRoot;//保存根接点的句柄
HTREEITEM hTreeSub;//保存第一层子接点的句柄
HTREEITEM hTreeSub1;//保存第二层子接点的句柄
//添加根接点,InsertItem的第二个默认为TVI_ROOT
hTreeRoot = m_treeCtrl.InsertItem("Root");
char cPath[256];
memset(cPath,0,256);
HMODULE module = GetModuleHandle(0);
GetModuleFileName(module,cPath,256);
CString strPath(cPath);
int pos = strPath.ReverseFind('\\');
if(pos == 0)
{
MessageBox("路径为空");
return;
}
strPath = strPath.Left(pos);
strPath.Format("%s\\FileName.txt",strPath);
std::string strPath1 = CStringA(strPath);
FILE* pFile = fopen(strPath1.c_str(),"r");
if (pFile == NULL)
{
MessageBox("文件打开失败");
return;
}
char cData[256];
memset(cData,0,256);
fgets(cData,256,pFile);
while (strcmp(cData,"")!=0)
{
CString strData(cData);
if (strData.GetLength() != 0)
{
int pos1 = strData.Find(':');
if (pos1 == 0)
{
hTreeSub = m_treeCtrl.InsertItem(strData,hTreeRoot);
continue;
}
CString strTreeName = strData.Left(pos1);
hTreeSub = m_treeCtrl.InsertItem(strTreeName,hTreeRoot);
strData = strData.Right(strData.GetLength()-pos1-1);
while ((pos1 = strData.Find(','))!=-1)
{
strTreeName = strData.Left(pos1);
hTreeSub1 = m_treeCtrl.InsertItem(strTreeName,hTreeSub);
strData = strData.Right(strData.GetLength()-pos1-1);
}
if (strData.GetLength()!=0)
{
strTreeName = strData;
hTreeSub1 = m_treeCtrl.InsertItem(strTreeName,hTreeSub);
}
}
memset(cData,0,256);
fgets(cData,256,pFile);
}
fclose(pFile);
m_treeCtrl.Expand(hTreeRoot,TVE_EXPAND);//Expand展开树状结构
}
其中接点前变成可选的状态,则是将CTreeCtrl控件的属性中的Checks Boxs的属性改为TRUE就可以了。
Name前面的加减收缩符号,则是通过将属性Has Buttons改为TRUE。
这两种可以通过相应的语言来设置。
2、当选中父接点时,该父接点下的所有子接点也被选中。
CtreeCtrl的HitTest函数能够得到与当前鼠标位置相关的项,所以可以先获取当前鼠标的位置,然后根据鼠标坐标获取该范围内的接点句柄。CTreeCtrl的GetChildItem方法可以获取当前句柄的孩子接点的句柄,所以可以根据父子接点的上下级关系实现子接点状态的修改。首先可以添加CTreeCtrl对象的NM_CLICK方法。具体实现如下:
CtreeCtrl的HitTest函数能够得到与当前鼠标位置相关的项,所以可以先获取当前鼠标的位置,然后根据鼠标坐标获取该范围内的接点句柄。CTreeCtrl的GetChildItem方法可以获取当前句柄的孩子接点的句柄,所以可以根据父子接点的上下级关系实现子接点状态的修改。首先可以添加CTreeCtrl对象的NM_CLICK方法。具体实现如下:
void CDialogStudyDlg::OnNMClickTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
UINT uFlag;
CPoint point;
::GetCursorPos(&point);
::ScreenToClient(m_treeCtrl.m_hWnd, &point);
HTREEITEM hItem = m_treeCtrl.HitTest(point,&uFlag);//HitTest函数能够得到与当前鼠标位置相关的项的句柄
//把所有的状态都随之修改
if ( NULL != hItem )
{
if ( uFlag & TVHT_ONITEMSTATEICON )//若点击CHECKBOX则传递TVHT_ONITEMSTATEICON
{
m_treeCtrl.SelectItem(hItem);//将当前选中的父接点或子接点高亮
bool ItemState = !m_treeCtrl.GetCheck( hItem );//设置树状结构的状态,当前状态取反则以
HTREEITEM hLayer1 = m_treeCtrl.GetChildItem( hItem );//获取当前接点的子接点第一个句柄
while ( NULL != hLayer1 )
{
m_treeCtrl.SetCheck( hLayer1 , ItemState );//设置当前接点的状态
HTREEITEM hLayer2 = m_treeCtrl.GetChildItem( hLayer1 );
while( NULL != hLayer2 )
{
m_treeCtrl.SetCheck( hLayer2 , ItemState );
hLayer2 = m_treeCtrl.GetNextItem( hLayer2 , TVGN_NEXT );
}
hLayer1 = m_treeCtrl.GetNextItem( hLayer1 , TVGN_NEXT );//获取子接点中的下一个接点的句柄
}
}
}
*pResult = 0;
}
效果如下:
先写到这些,后续学到别的继续添加。