一 基礎操作
1 插入節點
1)插入根節點
- //插入根節點
- HTREEITEM hRoot;
- CString str=L"ROOT"
- hRoot=nTreeCtrl.InsertItem(str);
- //相當於
- hRoot=nTreeCtrl.InsertItem(str,TVI_ROOT,TVI_LAST);
2)插入孩子節點
- //添加hRoot節點的孩子節點,並且被添加的節點位於hRoot所有孩子節點的末尾
- HTREEITEM hChild=nTreeCtrl.InsertItem(str,hRoot);
- //相當於
- HTREEITEM hChild=nTreeCtrl.InsertItem(str,hRoot,TVI_LAST);
2 獲得節點句柄
- //獲得根節點
- 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 判斷某節點是否有孩子節點
- //判斷某節點是否有孩子節點
- if (nTreeCtrl.ItemHasChildren(hRoot))
4 展開或收縮子節點
- //展開
- if(nTreeCtrl.ItemHasChildren(hRoot))
- nTreeCtrl.Expand(hParentItem,TVE_EXPAND);
5 獲得第一個孩子節點的句柄
- //判斷某節點是否有孩子節點
- if (nTreeCtrl.ItemHasChildren(hRoot))
- {
- //獲得孩子節點
- HTREEITEM hChild=nTreeCtrl.GetChildItem(hRoot);
- }
6 遍歷hRoot下一層的所有孩子節點
- //判斷某節點是否有孩子節點
- if (nTreeCtrl.ItemHasChildren(hRoot))
- {
- //獲得孩子節點
- HTREEITEM hChild=nTreeCtrl.GetChildItem(hRoot);
- //遍歷hRoot下一層的所有孩子節點
- while(hChild)
- {
- hChild=nTreeCtrl.GetNextItem(hChild,TVGN_NEXT);
- }
- }
7 獲得某節點上的文字
- //獲得某節點上的文字
- CString str;
- nTreeCtrl.GetItemText(hRoot);
8 選擇某節點,並讓其獲得焦點
首先,TREE控件的樣式必須設置為TVS_SHOWSELALWAYS
其次: 選擇該節點
- treeCtrl.SelectItem(hItem);
最后,設置焦點
- treeCtrl.SetFocus();
Tree控件設置焦點后,會自動將焦點定位到選擇的節點上
9 清空樹控件
- <strong> nTreeCtrl.DeleteAllItems();</strong>
10 將指定目錄下的文件插入節點
- 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();
- }
- 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 將文件列表中的文件插入樹控件中
- 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++;
- }
- }
- 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:
TVN_ITEMEXPANDING pnmtv = (NM_TREEVIEW FAR *) lParam
pnmtv
- Pointer to an NM_TREEVIEW structure. The itemNew member is a TVITEM structure that contains valid information about the parent item in the hItem, state, and lParam members. The action member indicates whether the list is to expand or collapse. For a list of possible values, see the description of the TVM_EXPAND message.
。。。。。。。。。
- typedef struct _NM_TREEVIEW {
- NMHDR hdr;
- UINT action;
- TV_ITEM itemOld;
- TV_ITEM itemNew;
- POINT ptDrag;
- } NM_TREEVIEW;
- typedef NM_TREEVIEW FAR* LPNM_TREEVIEW;
- 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中 存放着要展開項的句柄
解決:查了這么多,其實很簡單 代碼如下:
- void CLeftView::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
- {
- LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
- // TODO: 在此添加控件通知處理程序代
- HTREEITEM htree=pNMTreeView->itemNew.hItem; // 這個就是 將要被擴展或收縮節點的句柄
- 。。。
- }
2 怎么知道CTreeCtrl的一個節點是展開的還是收縮着的
解決:
方法1
- <strong> (GetItemState(hItem, TVIS_EXPANDED )&TVIS_EXPANDED)!=TVIS_EXPANDED //如果相等,則說明改節點是擴展的,如果不相等,則說明該節點是收縮的</strong>
方法2
響應TVN_ITEMEXPANDING事件時:
- void CExampleDlg::OnItemexpandingTree1(NMHDR* pNMHDR, LRESULT* pResult)
- {
- NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
- if (pNMTreeView->action == TVE_COLLAPSE) //判斷action的值
- 。。。
- 。。。
- }
3 判斷節點是否被擴展過
- if ((GetTreeCtrl().GetItemState(hItem,TVIS_EXPANDEDONCE )&TVIS_EXPANDEDONCE )!=0 ) //判斷是否擴展過一次,若!=0則說明被擴展過
4 使用 CImageList m_ImageList; 加載位圖或圖標,並將其與樹控件聯系在一起,由此便可以設置每個節點的圖標
- 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); // 樹控件和圖像列表相連
- m_treeCtrl.SetItemImage(htree,0,0) // 通過SetItemImage(htree,0,0) 設置節點的圖標
5 什么時候響應OnItemexpanding 消息
當節點第一次被展開時,才響應此消息。也就是說:當以開后該節點再展開或收縮時,便不再響應此消息了。
6 設置樹控件形式為 TVS_HASBUTTONS|TVS_LINESATROOT 時, 樹控件節點前才會出現+ - 號
以下為綜合例子: 點擊按鈕上一個 顯示該節點的上一個兄弟節點,並更改控件焦點
設置控件樣式:
- BOOL CTreePathView::PreCreateWindow(CREATESTRUCT& cs)
- {
- // TODO: 在此處通過修改
- // CREATESTRUCT cs 來修改窗口類或樣式
- cs.style|=TVS_HASLINES|TVS_SHOWSELALWAYS; //若是想用CImageList的圖標 ,則不要設置為TVS_HASBUTTONS形式
- return CTreeView::PreCreateWindow(cs);
- }
點擊按鈕5(焦點移動到上一個兄弟節點)
- 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);
- }
- }
- }
點擊按鈕6(焦點移動到下一個兄弟節點)
- 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) 獲得根節點句柄
- CTreeCtrl& nTreeCtrl=((CImportTreeView*)m_SplitterWnd.GetPane(0,0))->GetTreeCtrl();
- HTREEITEM hItem;
- //獲得根目錄節點
- hItem = nTreeCtrl.GetRootItem();
- //遍歷樹控件節點
- TreeVisit(&nTreeCtrl,hItem);
2)遍歷所有節點
- 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節點的全路徑
- CString m_ParentFolder[10];
- CString m_OldParentFolder[10];
- //--------------------將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節點路徑的函數
- 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;
- }
獲得葉子節點的函數
- 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)葉子節點
- //本地是否存在此文章
- 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)目錄節點
- 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 獲得樹中所有葉子節點的父目錄
即:樹中可能有許多枝干,獲取這些枝干的路徑
- std::vector<CString> m_BookDirectory; //存放所有葉子節點的父目錄
- 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);
- }
- }
- CTreeCtrl& nTreeCtrl=((CImportTreeView*)m_SplitterWnd.GetPane(0,0))->GetTreeCtrl();
- HTREEITEM hItem;
- hItem = nTreeCtrl.GetRootItem();
- m_BookDirectory.clear();
- GetBookDirectory(&nTreeCtrl,hItem); //獲得幾本書 及書的路徑
10 利用InsertItem、SetItemData 存放與該節點有關的數字信息
- 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
- BOOL SetItemData(
- HTREEITEM hItem,
- DWORD_PTR dwData
- );