CTreeCtrl 控件使用总结
2016-02-18 20:28
393 查看
一 基础操作
1 插入节点
1)插入根节点
[cpp] view
plaincopy
//插入根节点
HTREEITEM hRoot;
CString str=L"ROOT"
hRoot=nTreeCtrl.InsertItem(str);
//相当于
hRoot=nTreeCtrl.InsertItem(str,TVI_ROOT,TVI_LAST);
2)插入孩子节点
[cpp] view
plaincopy
//加入hRoot节点的孩子节点,而且被加入的节点位于hRoot全部孩子节点的末尾
HTREEITEM hChild=nTreeCtrl.InsertItem(str,hRoot);
//相当于
HTREEITEM hChild=nTreeCtrl.InsertItem(str,hRoot,TVI_LAST);
2 获得节点句柄
[cpp] view
plaincopy
//获得根节点
HTREEITEM hRootItem;
hRootItem=nTreeCtrl.GetRootItem();
//获得当前节点
HTREEITEM hCurrentItem;
hCurrentItem=nTreeCtrl.GetSelectedItem();
//获得hItem的前一个节点
HTREEITEM hPreItem;
hPreItem=nTreeCtrl.GetNextItem(hItem,TVGN_PREVIOUS);
//获得hItem的下一个节点
HTREEITEM hNextItem;
hNextItem=nTreeCtrl.GetNextItem(hItem,TVGN_NEXT);
3 推断某节点是否有孩子节点
[cpp] view
plaincopy
//推断某节点是否有孩子节点
if (nTreeCtrl.ItemHasChildren(hRoot))
4 展开或收缩子节点
[cpp] view
plaincopy
//展开
if(nTreeCtrl.ItemHasChildren(hRoot))
nTreeCtrl.Expand(hParentItem,TVE_EXPAND);
5 获得第一个孩子节点的句柄
[cpp] view
plaincopy
//推断某节点是否有孩子节点
if (nTreeCtrl.ItemHasChildren(hRoot))
{
//获得孩子节点
HTREEITEM hChild=nTreeCtrl.GetChildItem(hRoot);
}
6 遍历hRoot下一层的全部孩子节点
[cpp] view
plaincopy
//推断某节点是否有孩子节点
if (nTreeCtrl.ItemHasChildren(hRoot))
{
//获得孩子节点
HTREEITEM hChild=nTreeCtrl.GetChildItem(hRoot);
//遍历hRoot下一层的全部孩子节点
while(hChild)
{
hChild=nTreeCtrl.GetNextItem(hChild,TVGN_NEXT);
}
}
7 获得某节点上的文字
[cpp] view
plaincopy
//获得某节点上的文字
CString str;
nTreeCtrl.GetItemText(hRoot);
8 选择某节点。并让其获得焦点
首先,TREE控件的样式必须设置为TVS_SHOWSELALWAYS
其次: 选择该节点
[html] view
plaincopy
treeCtrl.SelectItem(hItem);
最后,设置焦点
[html] view
plaincopy
treeCtrl.SetFocus();
Tree控件设置焦点后,会自己主动将焦点定位到选择的节点上
9 清空树控件
[cpp] view
plaincopy
<strong> nTreeCtrl.DeleteAllItems();</strong>
10 将指定文件夹下的文件插入节点
[cpp] view
plaincopy
void InsertPath(CString path, HTREEITEM hRoot, CTreeCtrl& ctrl)
{
CFileFind nFindFile;
CString str=L"";
CString nPicFileName=L"";
BOOL IsExist=FALSE;
HTREEITEM hSubItem;
nPicFileName.Format(L"%s\\*.*",path);
IsExist = nFindFile.FindFile(nPicFileName);
while (IsExist)
{
IsExist = nFindFile.FindNextFile();
if(nFindFile.IsDots())
continue;
nPicFileName = nFindFile.GetFileName();
//路径
if(nFindFile.IsDirectory())
{
hSubItem = ctrl.InsertItem(nPicFileName,hRoot);
InsertPath(nFindFile.GetFilePath(),hSubItem,ctrl);
}
else
{
//文件
str = nPicFileName.Right(4);
if(!str.CompareNoCase(_T(".jpg")) || !str.CompareNoCase(_T(".tif")))
{
ctrl.InsertItem(nPicFileName,hRoot);
}
}
}
nFindFile.Close();
}
[cpp] view
plaincopy
void LoadPath(CString path) //path为指定文件夹 此函数的作用为将path文件夹下的文件插入树控件中
{
CTreeCtrl& ctrl = GetTreeCtrl();
ASSERT(ctrl);
ctrl.DeleteAllItems();
HTREEITEM hRoot = ctrl.InsertItem(path);
InsertPath(path,hRoot,ctrl);
ctrl.Expand(hRoot,TVE_EXPAND);
}
11 将文件列表中的文件插入树控件中
[cpp] view
plaincopy
void InsetAllFile( list<CString>& filePathList){
CTreeCtrl & nTreeCtrl=((CMyTreeView*)(((CMainFrame*)AfxGetMainWnd())->m_SplitterWnd.GetPane(0,0)))->GetTreeCtrl();
nTreeCtrl.DeleteAllItems();
list<CString>::iterator it=filePathList.begin();
HTREEITEM hRoot=NULL;
CString filePath;
CString treeRootName=L"根文件夹"; //全部的文件都在根文件夹下 即:默认全部的文件都在同一个文件夹下
while(it!=filePathList.end())
{
filePath=*it;
if(hRoot==NULL)
hRoot=nTreeCtrl.InsertItem(treeRootName); //建立根文件夹
if(filePath.Find(treeRootName)==0) // 文件第一层文件夹与根文件夹同样,则截去文件第一层文件夹。文件从第二层文件夹開始
filePath=filePath.Right(filePath.GetLength()-treeRootName.GetLength()-1);
LoadPicFiles(nTreeCtrl,filePath, hRoot);
it++;
}
}
[cpp] view
plaincopy
void LoadPicFiles(CTreeCtrl& nTreeCtrl, CString nFilePath, HTREEITEM nRoot)
{
// 推断nPicFolder是文件夹还是文件
// 假设是文件
// 直接将文件插入到树控件中 nTreeCtrl.InsertItem(nPicFolder,nRoot);
// 假设是文件夹
// 获取nPicFolder的第一层文件夹
// 推断nRoot文件夹下是否已经有此层文件夹
// 假设有此层文件夹
// 递归插入其它
// 假设无此层文件夹
// 插入此层文件夹,然后递归插入其它
CString nSubFolder; //首层文件夹
CString nSubFilePath; //去掉首层文件夹后的文件名称
BOOL IsExist=FALSE;
int nIndex=-1;
nIndex=nFilePath.Find(L'\\');
if(nIndex>=0) //文件夹
{
nSubFolder=nFilePath.Left(nIndex);
nSubFilePath=nFilePath.Right(nFilePath.GetLength()-nIndex-1);
HTREEITEM nSubRoot=NULL;
if(nTreeCtrl.ItemHasChildren(nRoot))
nSubRoot=nTreeCtrl.GetChildItem(nRoot);
CString str;
BOOL bExist=FALSE;
while(nSubRoot)
{
str=nTreeCtrl.GetItemText(nSubRoot);
if (str.CompareNoCase(nSubFolder)==0)
{
bExist=TRUE;
break;
}
nSubRoot=nTreeCtrl.GetNextSiblingItem(nSubRoot);
}
if(!bExist)
{
nSubRoot=nTreeCtrl.InsertItem(nSubFolder,nRoot);
LoadPicFiles(nTreeCtrl,nSubFilePath,nSubRoot);
}else{
LoadPicFiles(nTreeCtrl,nSubFilePath,nSubRoot);
}
}
else if(nFilePath.Find(L".jpg")!=-1 || nFilePath.Find(L".tif")!=-1)
{
nTreeCtrl.InsertItem(nFilePath,nRoot);
}
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
二 扩展操作
1 响应TVN_ITEMEXPANDING 消息时 怎样获得将要展开或收缩的那一个节点的句柄
MSDN:
Pointer to an NM_TREEVIEW structure.
The itemNew member is aTVITEM structure that contains valid information about the parent
item in thehItem,state, andlParam members. Theaction member indicates whether the list is to expand or collapse. For a list of possible values, see the description of theTVM_EXPAND message.
。。。
。
。。
。。。
[cpp] view
plaincopy
typedef struct _NM_TREEVIEW {
NMHDR hdr;
UINT action;
TV_ITEM itemOld;
TV_ITEM itemNew;
POINT ptDrag;
} NM_TREEVIEW;
typedef NM_TREEVIEW FAR* LPNM_TREEVIEW;
[cpp] view
plaincopy
typedef struct _TV_ITEM { tvi
UINT mask;
HTREEITEM hItem;
UINT state;
UINT stateMask;
LPSTR pszText;
int cchTextMax;
int iImage;
int iSelectedImage;
int cChildren;
LPARAM lParam; }
TV_ITEM, FAR* LPTV_ITEM;
在 TV_ITEM 的 hItem中 存放着要展开项的句柄
解决:查了这么多,事实上非常easy 代码例如以下:
[cpp] view
plaincopy
void CLeftView::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此加入控件通知处理程序代
HTREEITEM htree=pNMTreeView->itemNew.hItem; // 这个就是 将要被扩展或收缩节点的句柄
。。。
}
2 怎么知道CTreeCtrl的一个节点是展开的还是收缩着的
解决:
方法1
[cpp] view
plaincopy
<strong> (GetItemState(hItem, TVIS_EXPANDED )&TVIS_EXPANDED)!=TVIS_EXPANDED //假设相等,则说明改节点是扩展的,假设不相等,则说明该节点是收缩的</strong>
方法2
响应TVN_ITEMEXPANDING事件时:
[cpp] view
plaincopy
void CExampleDlg::OnItemexpandingTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
if (pNMTreeView->action == TVE_COLLAPSE) //推断action的值
。。。
。。。
}
3 推断节点是否被扩展过
[cpp] view
plaincopy
if ((GetTreeCtrl().GetItemState(hItem,TVIS_EXPANDEDONCE )&TVIS_EXPANDEDONCE )!=0 ) //推断是否扩展过一次,若!=0则说明被扩展过
4 使用 CImageList m_ImageList; 载入位图或图标。并将其与树控件联系在一起。由此便能够设置每一个节点的图标
[cpp] view
plaincopy
CImageList m_ImageList;
m_ImageList.Create(12,12,ILC_COLORDDB | ILC_MASK, 3, 1);
HICON hAdd=::LoadIcon(::AfxGetInstanceHandle(), (LPCTSTR)IDI_ADD);
HICON hRemove=::LoadIcon(::AfxGetInstanceHandle(), (LPCTSTR)IDI_REMOVE);
HICON hLeaf=::LoadIcon(::AfxGetInstanceHandle(), (LPCTSTR)IDI_LEAF);
m_ImageList.Add(hAdd);
m_ImageList.Add(hRemove);
m_ImageList.Add(hLeaf);
GetTreeCtrl().SetImageList(&m_ImageList,TVSIL_NORMAL); // 树控件和图像列表相连
[cpp] view
plaincopy
m_treeCtrl.SetItemImage(htree,0,0) // 通过SetItemImage(htree,0,0) 设置节点的图标
5 什么时候响应OnItemexpanding 消息
当节点第一次被展开时,才响应此消息。也就是说:当以开后该节点再展开或收缩时,便不再响应此消息了。
6 设置树控件形式为 TVS_HASBUTTONS|TVS_LINESATROOT 时, 树控件节点前才会出现+ - 号
下面为综合样例: 点击button上一个 显示该节点的上一个兄弟节点。并更改控件焦点
设置控件样式:
[html] view
plaincopy
BOOL CTreePathView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过改动
// CREATESTRUCT cs 来改动窗体类或样式
cs.style|=TVS_HASLINES|TVS_SHOWSELALWAYS; //若是想用CImageList的图标 ,则不要设置为TVS_HASBUTTONS形式
return CTreeView::PreCreateWindow(cs);
}
点击button5(焦点移动到上一个兄弟节点)
[html] view
plaincopy
void NewImageView::OnBnClickedButton5() // 上一个图
{
// TODO: 在此加入控件通知处理程序代码
CTreePathView * pTree=(CTreePathView* )(((CMainFrame *)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0));
CTreeCtrl & treeCtrl=pTree->GetTreeCtrl();
HTREEITEM hItem=treeCtrl.GetSelectedItem();
if (hItem!=NULL)
{
hItem=treeCtrl.GetNextItem(hItem,TVGN_PREVIOUS);
if (hItem!=NULL)
{
CString str;
str=pTree->GetFullPath(hItem);
SetImage(str);
treeCtrl.SelectItem(hItem);
treeCtrl.SetFocus();
InvalidateRect(m_ClientRect);
}
}
}
点击button6(焦点移动到下一个兄弟节点)
[html] view
plaincopy
void NewImageView::OnBnClickedButton6() //下一个
{
// TODO: 在此加入控件通知处理程序代码
CTreePathView * pTree=(CTreePathView* )(((CMainFrame *)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0));
CTreeCtrl & treeCtrl=pTree->GetTreeCtrl();
HTREEITEM hItem=treeCtrl.GetSelectedItem();
if (hItem!=NULL)
{
hItem=treeCtrl.GetNextItem(hItem,TVGN_NEXT);
if (hItem!=NULL)
{
CString str;
str=pTree->GetFullPath(hItem);
SetImage(str);
treeCtrl.SelectItem(hItem);
treeCtrl.SetFocus();
InvalidateRect(m_ClientRect);
}
}
}
7 遍历树控件的全部节点
1) 获得根节点句柄
[cpp] view
plaincopy
CTreeCtrl& nTreeCtrl=((CImportTreeView*)m_SplitterWnd.GetPane(0,0))->GetTreeCtrl();
HTREEITEM hItem;
//获得根文件夹节点
hItem = nTreeCtrl.GetRootItem();
//遍历树控件节点
TreeVisit(&nTreeCtrl,hItem);
2)遍历全部节点
[cpp] view
plaincopy
void TreeVisit(CTreeCtrl* pCtrl,HTREEITEM hItem)
{
if(pCtrl->ItemHasChildren(hItem))
{
HTREEITEM hChildItem = pCtrl->GetChildItem(hItem);
while(hChildItem!=NULL)
{
TreeVisit(pCtrl,hChildItem); //递归遍历孩子节点
hChildItem = pCtrl->GetNextItem(hChildItem, TVGN_NEXT);
}
}
else // 对叶子节点进行操作
Leaf(pCtrl,hItem);
}
8 获得某Item节点的全路径
[cpp] view
plaincopy
CString m_ParentFolder[10];
CString m_OldParentFolder[10];
[cpp] view
plaincopy
//--------------------将nParent加入到nParentFolder[10]第一位----------------------
BOOL AddParentFolder(CString nParentFolder[10], CString nParent)
{
for(int i=9;i>0;i--)
nParentFolder[i]=nParentFolder[i-1];
nParentFolder[0]=nParent;
return TRUE;
}
//---------------------nParentFolder[10]中的有效数据整合(加\)---------------------
CString AllCString(CString nParentFolder[10])
{
CString nAllCString=L"";
for(int i=0;i<10;i++)
{
if(nParentFolder[i]==L"") break;
nAllCString+=L"\\"+nParentFolder[i];
}
return nAllCString;
}
获得Item节点路径的函数
[cpp] view
plaincopy
CString GetItemPath(CTreeCtrl* pCtrl,HTREEITEM hItem)
{
CString nSelItemName=pCtrl->GetItemText(hItem);
HTREEITEM parentItem=pCtrl->GetParentItem(hItem);
if (parentItem==NULL) //hItem即为根文件夹
return nSelItemName;
//清空OLD
for(int i=0;i<10;i++) m_OldParentFolder[i]=L"";
//m_OldParentFolder 记录上一个节点的父节点
for(int i=0;i<10;i++)
m_OldParentFolder[i]=m_ParentFolder[i];
//m_ParentFolder 记录当前节点的父亲节点
for(int i=0;i<10;i++)
m_ParentFolder[i]=L"";
CString itemPath;
CString parentFolder=nSelItemName;
//将parentFolder加入到m_ParentFolder[0],其它值依次后移
AddParentFolder(m_ParentFolder,parentFolder);
// m_PicFolder 为根节点相应的名字
while(parentItem!=NULL&&pCtrl->GetItemText(parentItem).Compare(m_PicFolder))
{
parentFolder=pCtrl->GetItemText(parentItem);
AddParentFolder(m_ParentFolder,parentFolder);
parentItem=pCtrl->GetParentItem(parentItem);
}
itemPath.Format(L"%s%s",m_PicFolder,AllCString(m_ParentFolder));
//清空OLD
for(int i=0;i<10;i++) m_OldParentFolder[i]=L"";
//清空
for(int i=0;i<10;i++)
m_ParentFolder[i]=L"";
return itemPath;
}
获得叶子节点的函数
[cpp] view
plaincopy
void Leaf(CTreeCtrl* pCtrl,HTREEITEM hItem)
{
CString itemName=pCtrl->GetItemText(hItem);
// 叶子节点是jpg文件或tif文件
if(nSelItemName.Find(L".jpg")!=-1 || nSelItemName.Find(L".tif")!=-1)
{
//m_OldParentFolder 记录上一个节点的父节点
for(int i=0;i<10;i++)
m_OldParentFolder[i]=m_ParentFolder[i];
//m_ParentFolder 记录当前节点的父亲节点
for(int i=0;i<10;i++)
m_ParentFolder[i]=L"";
CString imgPath=L"";
CString parentFolder=itemName;
//将parentFolder加入到m_ParentFolder[0],其它值依次后移
AddParentFolder(m_ParentFolder,parentFolder);
HTREEITEM parentItem=pCtrl->GetParentItem(hItem);
// m_imgPath 为根节点相应的名字
while(pCtrl->GetItemText(parentItem).Compare(m_imgPath))
{
parentFolder=pCtrl->GetItemText(parentItem);
AddParentFolder(m_ParentFolder,parentFolder);
parentItem=pCtrl->GetParentItem(parentItem)
}
// 获得叶子节点的全路径
imgPath.Format(L"%s%s",m_imgPath,AllCString(m_ParentFolder));
}
// 对imgPath 所指的文件进行操作
ShowPic(imgPath);
}
上述方法过于繁杂,再来了简洁些的
使用栈。依次将本节点-->根节点入栈 出栈时顺序便为根节点-->本节点
1)叶子节点
[cpp] view
plaincopy
//本地是否存在此文章
void CMainFrame::PostPath(CTreeCtrl& nTreeCtrl, HTREEITEM hItem,CString &path)
{
stack<HTREEITEM> itemStack;
while (hItem!=nTreeCtrl.GetRootItem ())
{
itemStack.push(hItem);
hItem=nTreeCtrl.GetParentItem (hItem);
}
itemStack.push(nTreeCtrl.GetRootItem ());
CString itemName;
while (!itemStack.empty())
{
hItem=(HTREEITEM)itemStack.top();
itemStack.pop();
itemName=nTreeCtrl.GetItemText (hItem);
path+=itemName;
path+=L"\\";
}
path.TrimRight(L"\\");
path+=L".xml";
}
2)文件夹节点
[cpp] view
plaincopy
void CMainFrame::DirPath(CTreeCtrl& nTreeCtrl, HTREEITEM nRoot,CString &path)
{
stack<HTREEITEM> itemStack;
while (hItem!=nTreeCtrl.GetRootItem ())
{
itemStack.push(hItem);
hItem=nTreeCtrl.GetParentItem (hItem);
}
itemStack.push(nTreeCtrl.GetRootItem ());
CString itemName;
while (!itemStack.empty())
{
hItem=(HTREEITEM)itemStack.top();
itemStack.pop();
itemName=nTreeCtrl.GetItemText (hItem);
path+=itemName;
path+=L"\\";
}
}
9 获得树中全部叶子节点的父文件夹
即:树中可能有很多枝干,获取这些枝干的路径
[cpp] view
plaincopy
std::vector<CString> m_BookDirectory; //存放全部叶子节点的父文件夹
[cpp] view
plaincopy
void GetBookDirectory(CTreeCtrl* pCtrl,HTREEITEM hItem)
{
if(pCtrl->ItemHasChildren(hItem))
{
HTREEITEM hChildItem = pCtrl->GetChildItem(hItem);
while(hChildItem!=NULL)
{
GetBookDirectory(pCtrl,hChildItem); //递归遍历孩子节点
if(pCtrl->ItemHasChildren(hChildItem))
hChildItem = pCtrl->GetNextItem(hChildItem, TVGN_NEXT);
else
break;
}
}
else
{
HTREEITEM parentItem=pCtrl->GetParentItem(hItem);
CString bookPath=GetItemPath(pCtrl,parentItem);
m_BookDirectory.push_back(bookPath);
}
}
[cpp] view
plaincopy
CTreeCtrl& nTreeCtrl=((CImportTreeView*)m_SplitterWnd.GetPane(0,0))->GetTreeCtrl();
HTREEITEM hItem;
hItem = nTreeCtrl.GetRootItem();
m_BookDirectory.clear();
GetBookDirectory(&nTreeCtrl,hItem); //获得几本书 及书的路径
10 利用InsertItem、SetItemData 存放与该节点有关的数字信息
[cpp] view
plaincopy
HTREEITEM InsertItem(
LPCTSTR lpszItem,
int nImage, //实測范围0-65535
int nSelectedImage,
HTREEITEM hParent = TVI_ROOT,
HTREEITEM hInsertAfter = TVI_LAST
);
存放65535以上的大数据时 用SetItemData
A 32-bit application-specific value
[cpp] view
plaincopy
BOOL SetItemData(
HTREEITEM hItem,
DWORD_PTR dwData
);
1 插入节点
1)插入根节点
[cpp] view
plaincopy
//插入根节点
HTREEITEM hRoot;
CString str=L"ROOT"
hRoot=nTreeCtrl.InsertItem(str);
//相当于
hRoot=nTreeCtrl.InsertItem(str,TVI_ROOT,TVI_LAST);
2)插入孩子节点
[cpp] view
plaincopy
//加入hRoot节点的孩子节点,而且被加入的节点位于hRoot全部孩子节点的末尾
HTREEITEM hChild=nTreeCtrl.InsertItem(str,hRoot);
//相当于
HTREEITEM hChild=nTreeCtrl.InsertItem(str,hRoot,TVI_LAST);
2 获得节点句柄
[cpp] view
plaincopy
//获得根节点
HTREEITEM hRootItem;
hRootItem=nTreeCtrl.GetRootItem();
//获得当前节点
HTREEITEM hCurrentItem;
hCurrentItem=nTreeCtrl.GetSelectedItem();
//获得hItem的前一个节点
HTREEITEM hPreItem;
hPreItem=nTreeCtrl.GetNextItem(hItem,TVGN_PREVIOUS);
//获得hItem的下一个节点
HTREEITEM hNextItem;
hNextItem=nTreeCtrl.GetNextItem(hItem,TVGN_NEXT);
3 推断某节点是否有孩子节点
[cpp] view
plaincopy
//推断某节点是否有孩子节点
if (nTreeCtrl.ItemHasChildren(hRoot))
4 展开或收缩子节点
[cpp] view
plaincopy
//展开
if(nTreeCtrl.ItemHasChildren(hRoot))
nTreeCtrl.Expand(hParentItem,TVE_EXPAND);
5 获得第一个孩子节点的句柄
[cpp] view
plaincopy
//推断某节点是否有孩子节点
if (nTreeCtrl.ItemHasChildren(hRoot))
{
//获得孩子节点
HTREEITEM hChild=nTreeCtrl.GetChildItem(hRoot);
}
6 遍历hRoot下一层的全部孩子节点
[cpp] view
plaincopy
//推断某节点是否有孩子节点
if (nTreeCtrl.ItemHasChildren(hRoot))
{
//获得孩子节点
HTREEITEM hChild=nTreeCtrl.GetChildItem(hRoot);
//遍历hRoot下一层的全部孩子节点
while(hChild)
{
hChild=nTreeCtrl.GetNextItem(hChild,TVGN_NEXT);
}
}
7 获得某节点上的文字
[cpp] view
plaincopy
//获得某节点上的文字
CString str;
nTreeCtrl.GetItemText(hRoot);
8 选择某节点。并让其获得焦点
首先,TREE控件的样式必须设置为TVS_SHOWSELALWAYS
其次: 选择该节点
[html] view
plaincopy
treeCtrl.SelectItem(hItem);
最后,设置焦点
[html] view
plaincopy
treeCtrl.SetFocus();
Tree控件设置焦点后,会自己主动将焦点定位到选择的节点上
9 清空树控件
[cpp] view
plaincopy
<strong> nTreeCtrl.DeleteAllItems();</strong>
10 将指定文件夹下的文件插入节点
[cpp] view
plaincopy
void InsertPath(CString path, HTREEITEM hRoot, CTreeCtrl& ctrl)
{
CFileFind nFindFile;
CString str=L"";
CString nPicFileName=L"";
BOOL IsExist=FALSE;
HTREEITEM hSubItem;
nPicFileName.Format(L"%s\\*.*",path);
IsExist = nFindFile.FindFile(nPicFileName);
while (IsExist)
{
IsExist = nFindFile.FindNextFile();
if(nFindFile.IsDots())
continue;
nPicFileName = nFindFile.GetFileName();
//路径
if(nFindFile.IsDirectory())
{
hSubItem = ctrl.InsertItem(nPicFileName,hRoot);
InsertPath(nFindFile.GetFilePath(),hSubItem,ctrl);
}
else
{
//文件
str = nPicFileName.Right(4);
if(!str.CompareNoCase(_T(".jpg")) || !str.CompareNoCase(_T(".tif")))
{
ctrl.InsertItem(nPicFileName,hRoot);
}
}
}
nFindFile.Close();
}
[cpp] view
plaincopy
void LoadPath(CString path) //path为指定文件夹 此函数的作用为将path文件夹下的文件插入树控件中
{
CTreeCtrl& ctrl = GetTreeCtrl();
ASSERT(ctrl);
ctrl.DeleteAllItems();
HTREEITEM hRoot = ctrl.InsertItem(path);
InsertPath(path,hRoot,ctrl);
ctrl.Expand(hRoot,TVE_EXPAND);
}
11 将文件列表中的文件插入树控件中
[cpp] view
plaincopy
void InsetAllFile( list<CString>& filePathList){
CTreeCtrl & nTreeCtrl=((CMyTreeView*)(((CMainFrame*)AfxGetMainWnd())->m_SplitterWnd.GetPane(0,0)))->GetTreeCtrl();
nTreeCtrl.DeleteAllItems();
list<CString>::iterator it=filePathList.begin();
HTREEITEM hRoot=NULL;
CString filePath;
CString treeRootName=L"根文件夹"; //全部的文件都在根文件夹下 即:默认全部的文件都在同一个文件夹下
while(it!=filePathList.end())
{
filePath=*it;
if(hRoot==NULL)
hRoot=nTreeCtrl.InsertItem(treeRootName); //建立根文件夹
if(filePath.Find(treeRootName)==0) // 文件第一层文件夹与根文件夹同样,则截去文件第一层文件夹。文件从第二层文件夹開始
filePath=filePath.Right(filePath.GetLength()-treeRootName.GetLength()-1);
LoadPicFiles(nTreeCtrl,filePath, hRoot);
it++;
}
}
[cpp] view
plaincopy
void LoadPicFiles(CTreeCtrl& nTreeCtrl, CString nFilePath, HTREEITEM nRoot)
{
// 推断nPicFolder是文件夹还是文件
// 假设是文件
// 直接将文件插入到树控件中 nTreeCtrl.InsertItem(nPicFolder,nRoot);
// 假设是文件夹
// 获取nPicFolder的第一层文件夹
// 推断nRoot文件夹下是否已经有此层文件夹
// 假设有此层文件夹
// 递归插入其它
// 假设无此层文件夹
// 插入此层文件夹,然后递归插入其它
CString nSubFolder; //首层文件夹
CString nSubFilePath; //去掉首层文件夹后的文件名称
BOOL IsExist=FALSE;
int nIndex=-1;
nIndex=nFilePath.Find(L'\\');
if(nIndex>=0) //文件夹
{
nSubFolder=nFilePath.Left(nIndex);
nSubFilePath=nFilePath.Right(nFilePath.GetLength()-nIndex-1);
HTREEITEM nSubRoot=NULL;
if(nTreeCtrl.ItemHasChildren(nRoot))
nSubRoot=nTreeCtrl.GetChildItem(nRoot);
CString str;
BOOL bExist=FALSE;
while(nSubRoot)
{
str=nTreeCtrl.GetItemText(nSubRoot);
if (str.CompareNoCase(nSubFolder)==0)
{
bExist=TRUE;
break;
}
nSubRoot=nTreeCtrl.GetNextSiblingItem(nSubRoot);
}
if(!bExist)
{
nSubRoot=nTreeCtrl.InsertItem(nSubFolder,nRoot);
LoadPicFiles(nTreeCtrl,nSubFilePath,nSubRoot);
}else{
LoadPicFiles(nTreeCtrl,nSubFilePath,nSubRoot);
}
}
else if(nFilePath.Find(L".jpg")!=-1 || nFilePath.Find(L".tif")!=-1)
{
nTreeCtrl.InsertItem(nFilePath,nRoot);
}
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
二 扩展操作
1 响应TVN_ITEMEXPANDING 消息时 怎样获得将要展开或收缩的那一个节点的句柄
MSDN:
<strong>TVN_ITEMEXPANDING</strong> <em><a target=_blank target="_blank" class="synParam" href="http://blog.csdn.net/shuilan0066/article/details/6638504" style="color: rgb(255, 153, 0); text-decoration: none;">pnmtv</a></em> <strong>= (NM_TREEVIEW FAR *)</strong> <em>lParam</em>
pnmtv
Pointer to an NM_TREEVIEW structure.The itemNew member is aTVITEM structure that contains valid information about the parent
item in thehItem,state, andlParam members. Theaction member indicates whether the list is to expand or collapse. For a list of possible values, see the description of theTVM_EXPAND message.
。。。
。
。。
。。。
[cpp] view
plaincopy
typedef struct _NM_TREEVIEW {
NMHDR hdr;
UINT action;
TV_ITEM itemOld;
TV_ITEM itemNew;
POINT ptDrag;
} NM_TREEVIEW;
typedef NM_TREEVIEW FAR* LPNM_TREEVIEW;
[cpp] view
plaincopy
typedef struct _TV_ITEM { tvi
UINT mask;
HTREEITEM hItem;
UINT state;
UINT stateMask;
LPSTR pszText;
int cchTextMax;
int iImage;
int iSelectedImage;
int cChildren;
LPARAM lParam; }
TV_ITEM, FAR* LPTV_ITEM;
在 TV_ITEM 的 hItem中 存放着要展开项的句柄
解决:查了这么多,事实上非常easy 代码例如以下:
[cpp] view
plaincopy
void CLeftView::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此加入控件通知处理程序代
HTREEITEM htree=pNMTreeView->itemNew.hItem; // 这个就是 将要被扩展或收缩节点的句柄
。。。
}
2 怎么知道CTreeCtrl的一个节点是展开的还是收缩着的
解决:
方法1
[cpp] view
plaincopy
<strong> (GetItemState(hItem, TVIS_EXPANDED )&TVIS_EXPANDED)!=TVIS_EXPANDED //假设相等,则说明改节点是扩展的,假设不相等,则说明该节点是收缩的</strong>
方法2
响应TVN_ITEMEXPANDING事件时:
[cpp] view
plaincopy
void CExampleDlg::OnItemexpandingTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
if (pNMTreeView->action == TVE_COLLAPSE) //推断action的值
。。。
。。。
}
3 推断节点是否被扩展过
[cpp] view
plaincopy
if ((GetTreeCtrl().GetItemState(hItem,TVIS_EXPANDEDONCE )&TVIS_EXPANDEDONCE )!=0 ) //推断是否扩展过一次,若!=0则说明被扩展过
4 使用 CImageList m_ImageList; 载入位图或图标。并将其与树控件联系在一起。由此便能够设置每一个节点的图标
[cpp] view
plaincopy
CImageList m_ImageList;
m_ImageList.Create(12,12,ILC_COLORDDB | ILC_MASK, 3, 1);
HICON hAdd=::LoadIcon(::AfxGetInstanceHandle(), (LPCTSTR)IDI_ADD);
HICON hRemove=::LoadIcon(::AfxGetInstanceHandle(), (LPCTSTR)IDI_REMOVE);
HICON hLeaf=::LoadIcon(::AfxGetInstanceHandle(), (LPCTSTR)IDI_LEAF);
m_ImageList.Add(hAdd);
m_ImageList.Add(hRemove);
m_ImageList.Add(hLeaf);
GetTreeCtrl().SetImageList(&m_ImageList,TVSIL_NORMAL); // 树控件和图像列表相连
[cpp] view
plaincopy
m_treeCtrl.SetItemImage(htree,0,0) // 通过SetItemImage(htree,0,0) 设置节点的图标
5 什么时候响应OnItemexpanding 消息
当节点第一次被展开时,才响应此消息。也就是说:当以开后该节点再展开或收缩时,便不再响应此消息了。
6 设置树控件形式为 TVS_HASBUTTONS|TVS_LINESATROOT 时, 树控件节点前才会出现+ - 号
下面为综合样例: 点击button上一个 显示该节点的上一个兄弟节点。并更改控件焦点
设置控件样式:
[html] view
plaincopy
BOOL CTreePathView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过改动
// CREATESTRUCT cs 来改动窗体类或样式
cs.style|=TVS_HASLINES|TVS_SHOWSELALWAYS; //若是想用CImageList的图标 ,则不要设置为TVS_HASBUTTONS形式
return CTreeView::PreCreateWindow(cs);
}
点击button5(焦点移动到上一个兄弟节点)
[html] view
plaincopy
void NewImageView::OnBnClickedButton5() // 上一个图
{
// TODO: 在此加入控件通知处理程序代码
CTreePathView * pTree=(CTreePathView* )(((CMainFrame *)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0));
CTreeCtrl & treeCtrl=pTree->GetTreeCtrl();
HTREEITEM hItem=treeCtrl.GetSelectedItem();
if (hItem!=NULL)
{
hItem=treeCtrl.GetNextItem(hItem,TVGN_PREVIOUS);
if (hItem!=NULL)
{
CString str;
str=pTree->GetFullPath(hItem);
SetImage(str);
treeCtrl.SelectItem(hItem);
treeCtrl.SetFocus();
InvalidateRect(m_ClientRect);
}
}
}
点击button6(焦点移动到下一个兄弟节点)
[html] view
plaincopy
void NewImageView::OnBnClickedButton6() //下一个
{
// TODO: 在此加入控件通知处理程序代码
CTreePathView * pTree=(CTreePathView* )(((CMainFrame *)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0));
CTreeCtrl & treeCtrl=pTree->GetTreeCtrl();
HTREEITEM hItem=treeCtrl.GetSelectedItem();
if (hItem!=NULL)
{
hItem=treeCtrl.GetNextItem(hItem,TVGN_NEXT);
if (hItem!=NULL)
{
CString str;
str=pTree->GetFullPath(hItem);
SetImage(str);
treeCtrl.SelectItem(hItem);
treeCtrl.SetFocus();
InvalidateRect(m_ClientRect);
}
}
}
7 遍历树控件的全部节点
1) 获得根节点句柄
[cpp] view
plaincopy
CTreeCtrl& nTreeCtrl=((CImportTreeView*)m_SplitterWnd.GetPane(0,0))->GetTreeCtrl();
HTREEITEM hItem;
//获得根文件夹节点
hItem = nTreeCtrl.GetRootItem();
//遍历树控件节点
TreeVisit(&nTreeCtrl,hItem);
2)遍历全部节点
[cpp] view
plaincopy
void TreeVisit(CTreeCtrl* pCtrl,HTREEITEM hItem)
{
if(pCtrl->ItemHasChildren(hItem))
{
HTREEITEM hChildItem = pCtrl->GetChildItem(hItem);
while(hChildItem!=NULL)
{
TreeVisit(pCtrl,hChildItem); //递归遍历孩子节点
hChildItem = pCtrl->GetNextItem(hChildItem, TVGN_NEXT);
}
}
else // 对叶子节点进行操作
Leaf(pCtrl,hItem);
}
8 获得某Item节点的全路径
[cpp] view
plaincopy
CString m_ParentFolder[10];
CString m_OldParentFolder[10];
[cpp] view
plaincopy
//--------------------将nParent加入到nParentFolder[10]第一位----------------------
BOOL AddParentFolder(CString nParentFolder[10], CString nParent)
{
for(int i=9;i>0;i--)
nParentFolder[i]=nParentFolder[i-1];
nParentFolder[0]=nParent;
return TRUE;
}
//---------------------nParentFolder[10]中的有效数据整合(加\)---------------------
CString AllCString(CString nParentFolder[10])
{
CString nAllCString=L"";
for(int i=0;i<10;i++)
{
if(nParentFolder[i]==L"") break;
nAllCString+=L"\\"+nParentFolder[i];
}
return nAllCString;
}
获得Item节点路径的函数
[cpp] view
plaincopy
CString GetItemPath(CTreeCtrl* pCtrl,HTREEITEM hItem)
{
CString nSelItemName=pCtrl->GetItemText(hItem);
HTREEITEM parentItem=pCtrl->GetParentItem(hItem);
if (parentItem==NULL) //hItem即为根文件夹
return nSelItemName;
//清空OLD
for(int i=0;i<10;i++) m_OldParentFolder[i]=L"";
//m_OldParentFolder 记录上一个节点的父节点
for(int i=0;i<10;i++)
m_OldParentFolder[i]=m_ParentFolder[i];
//m_ParentFolder 记录当前节点的父亲节点
for(int i=0;i<10;i++)
m_ParentFolder[i]=L"";
CString itemPath;
CString parentFolder=nSelItemName;
//将parentFolder加入到m_ParentFolder[0],其它值依次后移
AddParentFolder(m_ParentFolder,parentFolder);
// m_PicFolder 为根节点相应的名字
while(parentItem!=NULL&&pCtrl->GetItemText(parentItem).Compare(m_PicFolder))
{
parentFolder=pCtrl->GetItemText(parentItem);
AddParentFolder(m_ParentFolder,parentFolder);
parentItem=pCtrl->GetParentItem(parentItem);
}
itemPath.Format(L"%s%s",m_PicFolder,AllCString(m_ParentFolder));
//清空OLD
for(int i=0;i<10;i++) m_OldParentFolder[i]=L"";
//清空
for(int i=0;i<10;i++)
m_ParentFolder[i]=L"";
return itemPath;
}
获得叶子节点的函数
[cpp] view
plaincopy
void Leaf(CTreeCtrl* pCtrl,HTREEITEM hItem)
{
CString itemName=pCtrl->GetItemText(hItem);
// 叶子节点是jpg文件或tif文件
if(nSelItemName.Find(L".jpg")!=-1 || nSelItemName.Find(L".tif")!=-1)
{
//m_OldParentFolder 记录上一个节点的父节点
for(int i=0;i<10;i++)
m_OldParentFolder[i]=m_ParentFolder[i];
//m_ParentFolder 记录当前节点的父亲节点
for(int i=0;i<10;i++)
m_ParentFolder[i]=L"";
CString imgPath=L"";
CString parentFolder=itemName;
//将parentFolder加入到m_ParentFolder[0],其它值依次后移
AddParentFolder(m_ParentFolder,parentFolder);
HTREEITEM parentItem=pCtrl->GetParentItem(hItem);
// m_imgPath 为根节点相应的名字
while(pCtrl->GetItemText(parentItem).Compare(m_imgPath))
{
parentFolder=pCtrl->GetItemText(parentItem);
AddParentFolder(m_ParentFolder,parentFolder);
parentItem=pCtrl->GetParentItem(parentItem)
}
// 获得叶子节点的全路径
imgPath.Format(L"%s%s",m_imgPath,AllCString(m_ParentFolder));
}
// 对imgPath 所指的文件进行操作
ShowPic(imgPath);
}
上述方法过于繁杂,再来了简洁些的
使用栈。依次将本节点-->根节点入栈 出栈时顺序便为根节点-->本节点
1)叶子节点
[cpp] view
plaincopy
//本地是否存在此文章
void CMainFrame::PostPath(CTreeCtrl& nTreeCtrl, HTREEITEM hItem,CString &path)
{
stack<HTREEITEM> itemStack;
while (hItem!=nTreeCtrl.GetRootItem ())
{
itemStack.push(hItem);
hItem=nTreeCtrl.GetParentItem (hItem);
}
itemStack.push(nTreeCtrl.GetRootItem ());
CString itemName;
while (!itemStack.empty())
{
hItem=(HTREEITEM)itemStack.top();
itemStack.pop();
itemName=nTreeCtrl.GetItemText (hItem);
path+=itemName;
path+=L"\\";
}
path.TrimRight(L"\\");
path+=L".xml";
}
2)文件夹节点
[cpp] view
plaincopy
void CMainFrame::DirPath(CTreeCtrl& nTreeCtrl, HTREEITEM nRoot,CString &path)
{
stack<HTREEITEM> itemStack;
while (hItem!=nTreeCtrl.GetRootItem ())
{
itemStack.push(hItem);
hItem=nTreeCtrl.GetParentItem (hItem);
}
itemStack.push(nTreeCtrl.GetRootItem ());
CString itemName;
while (!itemStack.empty())
{
hItem=(HTREEITEM)itemStack.top();
itemStack.pop();
itemName=nTreeCtrl.GetItemText (hItem);
path+=itemName;
path+=L"\\";
}
}
9 获得树中全部叶子节点的父文件夹
即:树中可能有很多枝干,获取这些枝干的路径
[cpp] view
plaincopy
std::vector<CString> m_BookDirectory; //存放全部叶子节点的父文件夹
[cpp] view
plaincopy
void GetBookDirectory(CTreeCtrl* pCtrl,HTREEITEM hItem)
{
if(pCtrl->ItemHasChildren(hItem))
{
HTREEITEM hChildItem = pCtrl->GetChildItem(hItem);
while(hChildItem!=NULL)
{
GetBookDirectory(pCtrl,hChildItem); //递归遍历孩子节点
if(pCtrl->ItemHasChildren(hChildItem))
hChildItem = pCtrl->GetNextItem(hChildItem, TVGN_NEXT);
else
break;
}
}
else
{
HTREEITEM parentItem=pCtrl->GetParentItem(hItem);
CString bookPath=GetItemPath(pCtrl,parentItem);
m_BookDirectory.push_back(bookPath);
}
}
[cpp] view
plaincopy
CTreeCtrl& nTreeCtrl=((CImportTreeView*)m_SplitterWnd.GetPane(0,0))->GetTreeCtrl();
HTREEITEM hItem;
hItem = nTreeCtrl.GetRootItem();
m_BookDirectory.clear();
GetBookDirectory(&nTreeCtrl,hItem); //获得几本书 及书的路径
10 利用InsertItem、SetItemData 存放与该节点有关的数字信息
[cpp] view
plaincopy
HTREEITEM InsertItem(
LPCTSTR lpszItem,
int nImage, //实測范围0-65535
int nSelectedImage,
HTREEITEM hParent = TVI_ROOT,
HTREEITEM hInsertAfter = TVI_LAST
);
存放65535以上的大数据时 用SetItemData
A 32-bit application-specific value
[cpp] view
plaincopy
BOOL SetItemData(
HTREEITEM hItem,
DWORD_PTR dwData
);
相关文章推荐
- JavaScript中记一个关于对象属性赋值的小问题
- Handler官方范例AsyncQueryHandler源码解析
- ASP.NET 后台代码的与前台文件“类”的关系
- C/C++ 函数参数和返回值传递机制
- 继承自NSObject的不常用又很有用的函数(2)
- JSP的自定义标签(二)之带属性的标签
- 刚设计的自动部署产品监控框架【图】
- 「打造自己的Library」SharedPreferences篇
- 电脑常识之GBK和GB2312的区别
- HDOJ 4990 Reading comprehension(矩阵快速幂)
- python面试问题题目
- 微信运动修改器python代码
- git 笔记
- mysql表结构查询
- linux之i2c子系统架构---总线驱动
- 回车换行知多少——关于回车换行的小插曲
- flask-sqlalchemy不同的关系的实例
- android基础--WebView
- USACO runaround
- 「深入Java」类型信息:RTTI和反射