ctreectrl_ctreectrl的问题 - CSDN
精华内容
参与话题
  • CTreeCtrl 控件使用总结

    万次阅读 热门讨论 2020-09-16 11:01:48
    一 基础操作 1 插入节点 1)插入根节点 //插入根节点 HTREEITEM hRoot; CString str=L"ROOT" hRoot=nTreeCtrl.InsertItem(str);... hRoot=nTreeCtrl.InsertItem(str,TVI_ROOT,TVI_LAST);...2)插...

     

     

     

     

     

     

     

    一 基础操作 

    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 = (NM_TREEVIEW FAR *) lParam

    pnmtv

    Pointer to an NM_TREEVIEW structure. TheitemNew 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.

    。。。。。。。。。

    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 
    );
     
    

     

     

     

    运用实例:

    古典书屋软件--内含大量古典小说   使用的便是CTreeCtrl这个控件

    下载链接:古典书屋软件下载——喜欢古典小说的不要错过奥

     

     

     

     

     

    展开全文
  • CTreeCtrl的基本用法

    2017-04-25 15:17:58
    1. 重载CTreeCtrl class CPopMenuTreeCtrl : public CTreeCtrl 2. 增加消息函数 void CPopMenuTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point) {  HTREEITEM hItem = HitTest(point,&nFlags);  S

     

    1.  重载CTreeCtrl

    class CPopMenuTreeCtrl : public CTreeCtrl

    2.  增加消息函数

    void CPopMenuTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point)

    {

           HTREEITEM hItem = HitTest(point,&nFlags);

            SelectItem(hItem);

           CTreeCtrl::OnLButtonDown(nFlags, point);

    }

     

    void CPopMenuTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point)

    {

           HTREEITEM hItem = HitTest(point,&nFlags);

          SelectItem(hItem);

           CTreeCtrl::OnLButtonDown(nFlags, point);

    }

    3.  在主对话框中增加树形数据的初始化

    void CMainDlg::OnDisplayType()

    {

           m_cTypeTree.DeleteAllItems();

           //增加根节点

           HTREEITEM hRoot = m_cTypeTree.InsertItem("分类管理");

           m_cTypeTree.SetItemData(hRoot,NULL_ITEM);

          

           //增加其他节点

           HTREEITEM hItem = NULL;

           for( int i=0; i<m_TypeList.size(); i++)

           {

                  hItem = m_cTypeTree.InsertItem(m_TypeList[i].GetName(),0,0,hRoot);

                  m_cTypeTree.SetItemData(hItem,m_TypeList[i].GetID());

           }

    }

    4.  在主对话框中增加消息函数

        void CMainDlg::OnClickTreeTrigger(NMHDR* pNMHDR, LRESULT* pResult)

    {

           HTREEITEM hItem = m_cTypeTree.GetSelectedItem();

           if(hItem != NULL)

           {

                  int nID = m_cTypeTree.GetItemData(hItem);

                  if(nID == NULL_ITEM)//根节点

                  {

                  }

                  else//子节点

                  {

                  }

           }

           *pResult = 0;

    }

     

    void CMainDlg::OnRclickTreeTrigger(NMHDR* pNMHDR, LRESULT* pResult)

    {

           HTREEITEM hItem = m_cTypeTree.GetSelectedItem();

           if(hItem != NULL)

           {

                  int nID = m_cTypeTree.GetItemData(hItem);

                  if(nID == NULL_ITEM)//根节点

                  {

                  }

                  else//子节点

                  {

                  }

           }

           *pResult = 0;

    }

    展开全文
  • CTreeCtrl的用法

    千次阅读 2016-12-05 13:42:27
    MFC中使用CTreeCtrl类来封装树形控件的各种操作。通过调用 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些树形控件的

    树形控件可以用于树形的结构,其中有一个根接点(Root)然后下面有许多子结点,而每个子结点上有允许有一个或多个或没有子结点。MFC中使用CTreeCtrl类来封装树形控件的各种操作。通过调用
    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些树形控件的专用风格:

    TVS_HASLINES 在父/子结点之间绘制连线

    TVS_LINESATROOT 在根/子结点之间绘制连线

    TVS_HASBUTTONS 在每一个结点前添加一个按钮,用于表示当前结点是否已被展开

    TVS_EDITLABELS 结点的显示字符可以被编辑

    TVS_SHOWSELALWAYS 在失去焦点时也显示当前选中的结点

    TVS_DISABLEDRAGDROP 不允许Drag/Drop

    TVS_NOTOOLTIPS 不使用ToolTip显示结点的显示字符

    在树形控件中每一个结点都有一个句柄(HTREEITEM),同时添加结点时必须提供的参数是该结点的父结点句柄,(其中根Root结点只有一个,既不可以添加也不可以删除)利用
    HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );可以添加一个结点,pszItem为显示的字符,hParent代表父结点的句柄,当前添加的结点会排在hInsertAfter表示的结点的后面,返回值为当前创建的结点的句柄。下面的代码会建立一个如下形式的树形结构:

    +--- Parent1 +--- Child1_1 +--- Child1_2 +--- Child1_3 +--- Parent2 +--- Parent3

    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);

    如果你希望在每个结点前添加一个小图标,就必需先调用CImageList* SetImageList( CImageList * pImageList, int nImageListType );指明当前所使用的ImageList,nImageListType为TVSIL_NORMAL。在调用完成后控件中使用图片以设置的 ImageList中图片为准。然后调用
    HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);添加结点,nImage为结点没被选中时所使用图片序号,nSelectedImage为结点被选中时所使用图片序号。下面的代码演示了ImageList的设置。

     

    m_list.Create(IDB_TREE,16,4,RGB(0,0,0));
    m_tree.SetImageList(&m_list,TVSIL_NORMAL);
    m_tree.InsertItem("Parent1",0,1); //添加,选中时显示图标1,未选中时显示图标0


    此外CTreeCtrl还提供了一些函数用于得到/修改控件的状态。
    HTREEITEM GetSelectedItem( );将返回当前选中的结点的句柄。BOOL SelectItem( HTREEITEM hItem );将选中指明结点。
    BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用于得到/修改某结点所使用图标索引。
    CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTR lpszItem );用于得到/修改某一结点的显示字符。
    BOOL DeleteItem( HTREEITEM hItem );用于删除某一结点,BOOL DeleteAllItems( );将删除所有结点。

    此外如果想遍历树可以使用下面的函数:
    HTREEITEM GetRootItem( );得到根结点。
    HTREEITEM GetChildItem( HTREEITEM hItem );得到子结点。
    HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明结点的上/下一个兄弟结点。
    HTREEITEM GetParentItem( HTREEITEM hItem );得到父结点。

    树形控件的消息映射使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode为通知代码,id为产生该消息的窗口ID,memberFxn为处理函数,函数的原型如同void OnXXXTree(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR为一数据结构,在具体使用时需要转换成其他类型的结构。对于树形控件可能取值和对应的数据结构为:

    TVN_SELCHANGED 在所选中的结点发生改变后发送,所用结构:NMTREEVIEW

    TVN_ITEMEXPANDED 在某结点被展开后发送,所用结构:NMTREEVIEW

    TVN_BEGINLABELEDIT 在开始编辑结点字符时发送,所用结构:NMTVDISPINFO

    TVN_ENDLABELEDIT 在结束编辑结点字符时发送,所用结构:NMTVDISPINFO

    TVN_GETDISPINFO 在需要得到某结点信息时发送,(如得到结点的显示字符)所用结构:NMTVDISPINFO

    关于ON_NOTIFY有很多内容,将在以后的内容中进行详细讲解。

    关于动态提供结点所显示的字符:首先你在添加结点时需要指明lpszItem参数为:LPSTR_TEXTCALLBACK。在控件显示该结点时会通过发送 TVN_GETDISPINFO来取得所需要的字符,在处理该消息时先将参数pNMHDR转换为LPNMTVDISPINFO,然后填充其中 item.pszText。但是我们通过什么来知道该结点所对应的信息呢,我的做法是在添加结点后设置其lParam参数,然后在提供信息时利用该参数来查找所对应的信息。下面的代码说明了这种方法:

    char szOut[8][3]={"No.1","No.2","No.3"}; //添加结点
    HTREEITEM hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...);
    m_tree.SetItemData(hItem, 0 );
    hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...)
    m_tree.SetItemData(hItem, 1 ); //处理消息 void
    CParentWnd::OnGetDispInfoTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR;
    pTVDI->item.pszText=szOut[pTVDI->item.lParam]; //通过lParam得到需要显示的字符在数组中的位置 *pResult = 0; }

    关于编辑结点的显示字符:首先需要设置树形控件的TVS_EDITLABELS风格,在开始编辑时该控件将会发送TVN_BEGINLABELEDIT,你可以通过在处理函数中返回TRUE来取消接下来的编辑,在编辑完成后会发送TVN_ENDLABELEDIT,在处理该消息时需要将参数pNMHDR转换为 LPNMTVDISPINFO,然后通过其中的item.pszText得到编辑后的字符,并重置显示字符。如果编辑在中途中取消该变量为NULL。下面的代码说明如何处理这些消息:

    //处理消息 TVN_BEGINLABELEDIT void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.lParam==0);//判断是否取消该操作 *pResult = 1; else *pResult = 0; } //处理消息 TVN_BEGINLABELEDIT void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.pszText==NULL);//判断是否已经取消取消编辑 m_tree.SetItemText(pTVDI->item.hItem,pTVDI->pszText); //重置显示字符 *pResult = 0; }

    上面讲述的方法所进行的消息映射必须在父窗口中进行(同样WM_NOTIFY的所有消息都需要在父窗口中处理)。

    1.取得或设定项目的信息.

    BOOL CTreeCtrl::GetItem(TV_ITEM* pItem);
    BOOL CTreeCtrl::SetItem(TV_ITEM* pItem);
    BOOL CTreeCtrl::SetItem(HTREEITEM hItem,UINTnMask,LPCTSTR lpszItem,int Image,int nSelectedImage,UINT nState,UINT nStateMask,LPARAME lParam);

    2.取得与设定项目的状态

    UINT CTreeCtrl::GetItemState(HTREEITEM hItem,UINT sStateMask)const;
    BOOL CTree Ctrl::SetItemState(HTREEITEM hItem,UINT nState,UINT nStateMask);

    3.取得与设定项目的图形

    BOOL CTreeCtrl::GetItemImage(HTREEITEM hItem,int& nImage,int& nSelectedImage)const;
    BOOL CTreeCtrl::SetItemImage(HTREEITEM hItem,int nImage,int nSelectedImage);

    4. 取得与设定项目的文本

    CString CTreeCtrl::GetItemText(HTREEITEM,hItem)const;
    BOOL CTreeCtrl::SetItemText(HTREEITEM hItem,LPCTSTR lpszItem);

    5. 查询 CTreeCtrl 中项目的个数

    UINT CTreeCtrl::GetCount();

    6.查询hItem 的父项目的句柄

    HTREEITEM CTreeCtrl::GetparenItem(HTREEITEM hItem);

    7.查询hItem是否有子项

    BOOL CTreeCtrl::ItemHasChildren(HTREEITEM hItem);

    8.取得hItem 第一个子项的句柄

    HTREEITEM CTreeCtrl::GetChildItem(HTREEITEM hItem);

    9.查询排在hItem前后的兄弟项

    HTREEITEM CTreeCtrl::GetPrevSiblingItem(HTREEITEM hItem);
    HTREEITEM CTreeCtrl::GetNextSiblingItem(HTREEITEM hItem);

    10.取得选中项的句柄 取得根项的句柄

    HTREEITEM CTreeCtrl::GetSelectedItem();

    HTREEITEM CTreeCtrl::GetRootItem();

     

     

     

     

    下面是树型视的三个结构TVINSERTSTRUCT、TVITEM、NMTREEVIEW

     

    TVINSERTSTRUCT


    包含添加新项到树形视控件所使用的信息。这个结构被TVM_INSERTITEM消息使用。这个结构与TV_INSERTSTRUCT结构是一样的,但它已经按当前的命名习惯重命名了。

    typedef struct tagTVINSERTSTRUCT {
    HTREEITEM hParent;
    HTREEITEM hInsertAfter;
    #if (_WIN32_IE >= 0x0400)
    union
    {
    TVITEMEX itemex;
    TVITEM item;
    } DUMMYUNIONNAME;
    #else
    TVITEM item;
    #endif
    } TVINSERTSTRUCT, FAR *LPTVINSERTSTRUCT;
    

    成员

    hParent
    父项的句柄。如果这个成员的值是TVI_ROOT或NULL,这项将被作为树形控件的根插入。
    hInsertAfter
    插入的新项之后的项的句柄。或是下列值之一: 值意味

    TVI_FIRST 在列表的开始插入项
    TVI_LAST 在列表的最后插入项
    TVI_ROOT 作为一个根项添加
    TVI_SORT 以字母顺序插入项
    itemex
    版本4.71TVITEMEX包含关于项添加的信息。
    item
    TVITEM包含关于项添加的信息。

    需求

      Windows NT/2000:需要Windows NT 3.51或更高版本。
      Windows 95/98:需要Windows 95或更高版本。
      Header:定义在commctrl.h。

    TVITEM

    指定或接收树形视项的属性。这个结构与TV_ITEM结构一样,但它已经被当前命名协议重新命名了。新的应用程序应该使用这个结构。

    
    typedef struct tagTVITEM{
    UINT mask;
    HTREEITEM hItem;
    UINT state;
    UINT stateMask;
    LPTSTR pszText;
    int cchTextMax;
    int iImage;
    int iSelectedImage;
    int cChildren;
    LPARAM lParam;
    } TVITEM, FAR *LPTVITEM;
    

    成员

    mask
    指出其它的结构成员哪些包含有效数据的标记数组。当这个结构被TVM_GETITEM消息使用时,mask成员指出项的属性被取回。这个成员可以是下列值的一个或多个。
    TVIF_CHILDREN cChildren成员是有效的。
    TVIF_DI_SETITEM 树形视控件将保留支持信息并且不重新请求它。当处理TVN_GETDISPINF通知时,这个标记是有效的。
    TVIF_HANDLE hItem成员有效。
    TVIF_IMAGE iImage成员有效。
    TVIF_PARAM lParam成员有效。
    TVIF_SELECTEDIMAGE iSelectedImage成员有效。
    TVIF_STATE statestateMask成员有效。
    TVIF_TEXT pszTextcchTextMax成员有效。
    hItem
    这个函数引用的项。
    state
    位标记和图像列表索引的设置,指出项的状态。当设置了一个项的状态,stateMask成员指出这个成员的位是有效的。当取加一个项的状态时,这个成员返回stateMask成员指出的位的当前状态。

    这个成员的0至7位包含了项的状态标记。关于可能的项状态标记,参见Tree View Control Item States.

    覆盖图像覆盖在项的图标图像之上。这个成员的8至11位指定了以1为基准的覆盖图像索引。如果这些位是0,这个项没有覆盖图像。要隔离这些位,使用TVIS_OVERLAYMASK掩码。要在这个成员中设置覆盖图像索引,使用INDEXTOOVERLAYMASK宏。图像列表的覆盖图像是被ImageList_SetOverlayImage函数设置的。

    一个状态图像是仅次于指出应用程序定义的状态的项的图标显示的。通过发送TVM_SETIMAGELIST消息来指定一个状态图像列表。要设置一个项的状态图像,在TVITEM结构的stateMask成员中包含TVIS_STATEIMAGEMASK值。结构的state成员的12至15位指定状态图像列表中被绘制图像的索引。

    要设置状态图像索引,使用INDEXTOSTATEIMAGEMASK。这个宏把一个索引适当的设置到12至15位上。要指出项没有状态图像,设置索引为0。这意味着在状态图像列表中的图像0不能被作为一个状态图像使用。要隔离state成员的位12至15,使用TVIS_STATEIMAGEMASK掩码。

    stateMask
    state成员的位是有效的。如果你取回了一个项的状态,设置stateMask成员的位来指出state成员中的这个位被返回。如果你设置了一个项的状态,设置stateMask成员的位来指出state成员的这个位是你想设置的。要设置或取回一个项的覆盖图像的索引,设置TVIS_OVERLAYMASK位。要设置和取回一个项的状态图像索引,设置TVIS_STATEIMAGEMASK位。
    pszText
    如果这个结构指定了项属性,那么这个成员是指向一个以空字符结束的字符串,包含有项的文本。如果这个成员是值LPSTR_TEXTCALLBACK,那么父窗口为保存名字负责。既然这样,当树形视控件需要显示、保存或编辑项文本时,向父窗口发送TVN_GETDISPINFO通过消息,当项文本改变时,发送TVN_SETDISPINFO通知消息。

    如果结构是取回项的属性,这个成员是取回项文本缓冲的地址。

    cchTextMax
    pszText成员指定缓冲的大小,以字符为单位。如果这个结构被使用来设置项属性,这个成员被忽略。
    iImage
    当项是在非选择状态中时,是树形控件的图像列表的索引。

    如果这个成员是值I_IMAGECALLBACK,父窗口为保存索引负责。既然这样,当树形视控件需要显示这个图像时,向父窗口发送TVN_GETDISPINFO通知消息来获得索引。

    iSelectedImage
    当项被选择时,是树形控件图像列表的索引。

    如果这个成员是值I_IMAGECALLBACK,父窗口为保存索引负责。既然这样,当树形视控件需要显示这个图像时,向父窗口发送TVN_GETDISPINFO通知消息来获得索引。

    cChildren
    标记指出哪一个项有关联的子项。这个成员可以是下列值之一。
    zero 这个项没有子项。
    one 这个项有一个或更多的子项。
    I_CHILDRENCALLBACK The parent window keeps track of whether the item has child items. In this case, when the tree view control needs to display the item, the control sends the parent a TVN_GETDISPINFO notification message to determine whether the item has child items.

    If the tree view control has the TVS_HASBUTTONS style, it uses this member to determine whether to display the button indicating the presence of child items. You can use this member to force the control to display the button even though the item does not have any child items inserted. This allows you to display the button while minimizing the control's memory usage by inserting child items only when the item is visible or expanded.

    lParam
    与这项相关的32位值。

    需要

      Windows NT/2000:需要Windows NT 3.51或更高版本。
      Windows 95/98:需要Windows 95或更高版本。
      Header:定义在commctrl.h。

    NMTREEVIEW


    包含关于树形视通知消息的信息。这个结构与NM_TREEVIEW结构一样,但它已经用当前的命名规则进行了重命名。

    typedef struct tagNMTREEVIEW {
    NMHDR hdr; 
    UINT action; 
    TVITEM itemOld; 
    TVITEM itemNew; 
    POINT ptDrag; 
    } NMTREEVIEW, FAR *LPNMTREEVIEW; 
    

    成员

    hdr
    NMHDR结构,包含了关于这个通知消息的信息
    action
    通知指定的动作标记。
    itemOld
    包含关于旧项状态信息的TVITEM结构。通知消息没有使用它时,这个成员为0。
    itemNew
    包含关于新项状态信息的TVITEM结构。通知消息没有使用它时,这个成员为0。
    ptDrag
    包含引起通知消息发送的事件信息的POINT结构。

    参见

    WM_NOTIFY

    展开全文
  • CTreeCtrlEx树控件完整多选

    千次阅读 2016-08-24 12:56:16
    定义CDirTreeCtrl m_tree;作为树控件变量 TreeCtrlEx.h [cpp] view plain copy .../************************************************************************/  .../* 

    定义CDirTreeCtrl m_tree;作为树控件变量

    TreeCtrlEx.h

    [cpp] view plain copy
    1. #pragma once  
    2.   
    3. /************************************************************************/  
    4. /*                                                                      */  
    5. /************************************************************************/  
    6.   
    7. #ifndef __TREECTRLEX_H  
    8. #define __TREECTRLEX_H  
    9.   
    10. #define TVGN_EX_ALL         0x000F  
    11.   
    12. /  
    13. // CTreeCtrlEx window  
    14.   
    15. class CTreeCtrlEx : public CTreeCtrl  
    16. {  
    17.     DECLARE_DYNAMIC(CTreeCtrlEx)  
    18.   
    19.     // Construction  
    20. public:  
    21.     CTreeCtrlEx() : m_bSelectPending(FALSE), m_hClickedItem(NULL), m_hFirstSelectedItem(NULL), m_bSelectionComplete(TRUE), m_bEditLabelPending(FALSE) {}  
    22.     BOOL Create(DWORD dwStyle, DWORD dwExStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);  
    23.     BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);  
    24.   
    25.     // Attributes  
    26. public:  
    27.     UINT GetSelectedCount() const;  
    28.     HTREEITEM GetNextItem(HTREEITEM hItem, UINT nCode);  
    29.     HTREEITEM GetFirstSelectedItem();  
    30.     HTREEITEM GetNextSelectedItem(HTREEITEM hItem);  
    31.     HTREEITEM GetPrevSelectedItem(HTREEITEM hItem);  
    32.     HTREEITEM ItemFromData(DWORD dwData, HTREEITEM hStartAtItem=NULL) const;  
    33.   
    34.     BOOL SelectItemEx(HTREEITEM hItem, BOOL bSelect=TRUE);  
    35.   
    36.     BOOL SelectItems(HTREEITEM hFromItem, HTREEITEM hToItem);  
    37.     void ClearSelection(BOOL bMultiOnly=FALSE) ;  
    38.   
    39. protected:  
    40.     void SelectMultiple( HTREEITEM hClickedItem, UINT nFlags, CPoint point );  
    41.   
    42. private:  
    43.     BOOL        m_bSelectPending;  
    44.     CPoint      m_ptClick;  
    45.     HTREEITEM   m_hClickedItem;  
    46.     HTREEITEM   m_hFirstSelectedItem;  
    47.     BOOL        m_bSelectionComplete;  
    48.     BOOL        m_bEditLabelPending;  
    49.     UINT        m_idTimer;  
    50.   
    51.     // Operations  
    52. public:  
    53.   
    54.     // Overrides  
    55.     // ClassWizard generated virtual function overrides  
    56.     //{{AFX_VIRTUAL(CTreeCtrlEx)  
    57.     //}}AFX_VIRTUAL  
    58.   
    59.     // Implementation  
    60. public:  
    61.     virtual ~CTreeCtrlEx() {}  
    62.   
    63.     // Generated message map functions  
    64. protected:  
    65.     //{{AFX_MSG(CTreeCtrlEx)  
    66.     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  
    67.     afx_msg void OnLButtonUp(UINT nFlags, CPoint point);  
    68.     afx_msg void OnMouseMove(UINT nFlags, CPoint point);  
    69.     afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);  
    70.     afx_msg BOOL OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult);  
    71.     afx_msg BOOL OnSetfocus(NMHDR* pNMHDR, LRESULT* pResult);  
    72.     afx_msg BOOL OnKillfocus(NMHDR* pNMHDR, LRESULT* pResult);  
    73.     afx_msg void OnRButtonDown(UINT nFlags, CPoint point);  
    74.     afx_msg BOOL OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult);  
    75.     afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);  
    76.     afx_msg void OnTimer(/*UINT*/UINT_PTR nIDEvent);  
    77.     //}}AFX_MSG  
    78.   
    79.     DECLARE_MESSAGE_MAP()  
    80. };  
    81.   
    82. /************************************************************************/  
    83. /*                                                                      */  
    84. /************************************************************************/  
    85.   
    86. class CDirTreeCtrl : public CTreeCtrlEx  
    87. {  
    88.     DECLARE_DYNAMIC(CDirTreeCtrl)  
    89.   
    90.     //data  
    91. private:  
    92.     BOOL AddSubDirAsItem(HTREEITEM hParent);  
    93.     BOOL AddSubDirAsItem1(HTREEITEM hParent);  
    94.   
    95.     BOOL FindSubDir(LPCTSTR strPath);  
    96.     CString GetFullPath(HTREEITEM hItem);  
    97.     BOOL DisplayDrives();  
    98.     BOOL AttachImgList();  
    99.     HTREEITEM AddItem( HTREEITEM hParent, LPCTSTR strName );  
    100.   
    101.     CString        m_strError;     
    102.     CImageList     m_imgList;  
    103.     HTREEITEM m_hDirTreeRoot;  
    104.     DWORD m_treeStyle;  
    105.   
    106. public:  
    107.     CDirTreeCtrl();  
    108.     void SetDirTreeStyle();  
    109.     BOOL DisplayTree(LPCTSTR strRoot);  
    110.     virtual ~CDirTreeCtrl();  
    111.   
    112.     // Generated message map functions  
    113. protected:  
    114.     //{{AFX_MSG(CDirTreeCtrl)  
    115.     // NOTE - the ClassWizard will add and remove member functions here.  
    116.     //}}AFX_MSG  
    117.     DECLARE_MESSAGE_MAP()  
    118.   
    119. public:  
    120.     //afx_msg void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult);   // 用这个作为鼠标消息响应也可以,但是下面的一个更好  
    121.     afx_msg void OnTvnItemexpanding(NMHDR *pNMHDR, LRESULT *pResult);  
    122. };  
    123.   
    124. HTREEITEM GetTreeItemFromData(CTreeCtrl& treeCtrl, DWORD dwData, HTREEITEM hStartAtItem=NULL);  
    125.   
    126. #endif  

    TreeCtrlEx.cpp

    [cpp] view plain copy
    1. #include "stdafx.h"  
    2. #include "TreeCtrlEx.h"  
    3.   
    4. IMPLEMENT_DYNAMIC(CTreeCtrlEx, CTreeCtrl)  
    5. IMPLEMENT_DYNAMIC(CDirTreeCtrl, CTreeCtrlEx)  
    6. // CDirTreeCtrl message handlers  
    7. CDirTreeCtrl::CDirTreeCtrl()  
    8. {  
    9. }  
    10.   
    11. CDirTreeCtrl::~CDirTreeCtrl()  
    12. {  
    13.     m_imgList.Detach();  
    14. }  
    15.   
    16. /************************************************************************/  
    17. /*                                                                      */  
    18. /************************************************************************/  
    19.   
    20. #ifdef _DEBUG  
    21. #define new DEBUG_NEW  
    22. #undef THIS_FILE  
    23. static char THIS_FILE[] = __FILE__;  
    24. #endif  
    25.   
    26. #define TCEX_EDITLABEL 1        // Edit label timer event  
    27.   
    28. /  
    29. // CTreeCtrlEx  
    30.   
    31. BEGIN_MESSAGE_MAP(CTreeCtrlEx, CTreeCtrl)  
    32.     //{{AFX_MSG_MAP(CTreeCtrlEx)  
    33.     ON_WM_LBUTTONDOWN()  
    34.     ON_WM_LBUTTONUP()  
    35.     ON_WM_MOUSEMOVE()  
    36.     ON_WM_KEYDOWN()  
    37.     ON_NOTIFY_REFLECT_EX(TVN_ITEMEXPANDING, OnItemexpanding)  
    38.     ON_NOTIFY_REFLECT_EX(NM_SETFOCUS, OnSetfocus)  
    39.     ON_NOTIFY_REFLECT_EX(NM_KILLFOCUS, OnKillfocus)  
    40.     ON_NOTIFY_REFLECT_EX(TVN_SELCHANGED, OnSelchanged)  
    41.     ON_WM_RBUTTONDOWN()  
    42.     ON_WM_LBUTTONDBLCLK()  
    43.     ON_WM_TIMER()  
    44.     //}}AFX_MSG_MAP  
    45. END_MESSAGE_MAP()  
    46.   
    47. //IMPLEMENT_DYNAMIC(CTreeCtrlEx, CTreeCtrl)  
    48.   
    49. BOOL CTreeCtrlEx::Create(DWORD dwStyle, DWORD dwExStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)  
    50. {  
    51. #if _MFC_VER < 0x0700  
    52.     return CreateEx( dwExStyle, WC_TREEVIEW, NULL, dwStyle,  
    53.         rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,   
    54.         pParentWnd->GetSafeHwnd(), (HMENU)nID );  
    55. #else  
    56.     return CTreeCtrl::CreateEx( dwExStyle, dwStyle, rect, pParentWnd, nID );  
    57. #endif  
    58. }  
    59.   
    60. BOOL CTreeCtrlEx::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)  
    61. {  
    62.     return CTreeCtrl::Create(dwStyle, rect, pParentWnd, nID);  
    63. }  
    64.   
    65.   
    66. /  
    67. // CTreeCtrlEx message handlers  
    68.   
    69.   
    70. ///  
    71. // The tree control dosn't support multiple selection. However we can simulate   
    72. // it by taking control of the left mouse click and arrow key press before the  
    73. // control gets them, and setting/clearing the TVIS_SELECTED style on the items  
    74.   
    75. void CTreeCtrlEx::OnLButtonDown( UINT nFlags, CPoint point )  
    76. {  
    77.   
    78.     UINT nHitFlags = 0;  
    79.     HTREEITEM hClickedItem = HitTest( point, &nHitFlags );  
    80.   
    81.     // Must invoke label editing explicitly. The base class OnLButtonDown would normally  
    82.     // do this, but we can't call it here because of the multiple selection...  
    83.     if( !( nFlags&( MK_CONTROL|MK_SHIFT ) ) && ( GetStyle() & TVS_EDITLABELS ) && ( nHitFlags & TVHT_ONITEMLABEL ) )  
    84.         if ( hClickedItem == GetSelectedItem() )  
    85.         {  
    86.             // Clear multple selection before label editing  
    87.             ClearSelection();  
    88.             SelectItem( hClickedItem );  
    89.   
    90.             // Invoke label editing  
    91.             m_bEditLabelPending = TRUE;  
    92.             m_idTimer = (UINT)SetTimer(TCEX_EDITLABEL, GetDoubleClickTime(), NULL);  
    93.   
    94.             return;  
    95.         }  
    96.   
    97.         m_bEditLabelPending = FALSE;  
    98.   
    99.         if( nHitFlags & TVHT_ONITEM )  
    100.         {  
    101.             SetFocus();  
    102.   
    103.             m_hClickedItem = hClickedItem;  
    104.   
    105.             // Is the clicked item already selected ?  
    106.             BOOL bIsClickedItemSelected = GetItemState( hClickedItem, TVIS_SELECTED ) & TVIS_SELECTED;  
    107.   
    108.             if ( bIsClickedItemSelected )  
    109.             {  
    110.                 // Maybe user wants to drag/drop multiple items!  
    111.                 // So, wait until OnLButtonUp() to do the selection stuff.   
    112.                 m_bSelectPending=TRUE;  
    113.             }  
    114.             else  
    115.             {  
    116.                 SelectMultiple( hClickedItem, nFlags, point );  
    117.                 m_bSelectPending=FALSE;  
    118.             }  
    119.   
    120.             m_ptClick=point;  
    121.         }  
    122.         else  
    123.             CTreeCtrl::OnLButtonDown( nFlags, point );  
    124. }  
    125.   
    126. void CTreeCtrlEx::OnLButtonUp( UINT nFlags, CPoint point )  
    127. {  
    128.     if ( m_bSelectPending )  
    129.     {  
    130.         // A select has been waiting to be performed here  
    131.         SelectMultiple( m_hClickedItem, nFlags, point );  
    132.         m_bSelectPending=FALSE;  
    133.     }  
    134.   
    135.     m_hClickedItem=NULL;  
    136.   
    137.     CTreeCtrl::OnLButtonUp( nFlags, point );  
    138. }  
    139.   
    140.   
    141. void CTreeCtrlEx::OnMouseMove( UINT nFlags, CPoint point )  
    142. {  
    143.     // If there is a select pending, check if cursor has moved so much away from the   
    144.     // down-click point that we should cancel the pending select and initiate  
    145.     // a drag/drop operation instead!  
    146.   
    147.     if ( m_hClickedItem )  
    148.     {  
    149.         CSize sizeMoved = m_ptClick-point;  
    150.   
    151.         if ( abs(sizeMoved.cx) > GetSystemMetrics( SM_CXDRAG ) || abs(sizeMoved.cy) > GetSystemMetrics( SM_CYDRAG ) )  
    152.         {  
    153.             m_bSelectPending=FALSE;  
    154.   
    155.             // Notify parent that he may begin drag operation  
    156.             // Since we have taken over OnLButtonDown(), the default handler doesn't  
    157.             // do the normal work when clicking an item, so we must provide our own  
    158.             // TVN_BEGINDRAG notification for the parent!  
    159.   
    160.             CWnd* pWnd = GetParent();  
    161.             if ( pWnd && !( GetStyle() & TVS_DISABLEDRAGDROP ) )  
    162.             {  
    163.                 NM_TREEVIEW tv;  
    164.   
    165.                 tv.hdr.hwndFrom = GetSafeHwnd();  
    166.                 tv.hdr.idFrom = GetWindowLong( GetSafeHwnd(), GWL_ID );  
    167.                 tv.hdr.code = TVN_BEGINDRAG;  
    168.   
    169.                 tv.itemNew.hItem = m_hClickedItem;  
    170.                 tv.itemNew.state = GetItemState( m_hClickedItem, 0xffffffff );  
    171.                 tv.itemNew.lParam = GetItemData( m_hClickedItem );  
    172.   
    173.                 tv.ptDrag.x = point.x;  
    174.                 tv.ptDrag.y = point.y;  
    175.   
    176.                 pWnd->SendMessage( WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv );  
    177.             }  
    178.   
    179.             m_hClickedItem=NULL;  
    180.         }  
    181.     }  
    182.   
    183.     CTreeCtrl::OnMouseMove( nFlags, point );  
    184. }  
    185.   
    186.   
    187. void CTreeCtrlEx::SelectMultiple( HTREEITEM hClickedItem, UINT nFlags, CPoint point )  
    188. {  
    189.     // Start preparing an NM_TREEVIEW struct to send a notification after selection is done  
    190.     NM_TREEVIEW tv;  
    191.     memset(&tv.itemOld, 0, sizeof(tv.itemOld));  
    192.   
    193.     CWnd* pWnd = GetParent();  
    194.   
    195.     HTREEITEM hOldItem = GetSelectedItem();  
    196.   
    197.     if ( hOldItem )  
    198.     {  
    199.         tv.itemOld.hItem = hOldItem;  
    200.         tv.itemOld.state = GetItemState( hOldItem, 0xffffffff );  
    201.         tv.itemOld.lParam = GetItemData( hOldItem );  
    202.         tv.itemOld.mask = TVIF_HANDLE|TVIF_STATE|TVIF_PARAM;  
    203.     }  
    204.   
    205.     // Flag signaling that selection process is NOT complete.  
    206.     // (Will prohibit TVN_SELCHANGED from being sent to parent)  
    207.     m_bSelectionComplete = FALSE;  
    208.   
    209.     // Action depends on whether the user holds down the Shift or Ctrl key  
    210.     if ( nFlags & MK_SHIFT )  
    211.     {  
    212.         // Select from first selected item to the clicked item  
    213.         if ( !m_hFirstSelectedItem )  
    214.             m_hFirstSelectedItem = GetSelectedItem();  
    215.   
    216.         SelectItems( m_hFirstSelectedItem, hClickedItem );  
    217.     }  
    218.     else if ( nFlags & MK_CONTROL )  
    219.     {  
    220.         // Find which item is currently selected  
    221.         HTREEITEM hSelectedItem = GetSelectedItem();  
    222.   
    223.         // Is the clicked item already selected ?  
    224.         BOOL bIsClickedItemSelected = GetItemState( hClickedItem, TVIS_SELECTED ) & TVIS_SELECTED;  
    225.         BOOL bIsSelectedItemSelected = FALSE;  
    226.         if ( hSelectedItem )  
    227.             bIsSelectedItemSelected = GetItemState( hSelectedItem, TVIS_SELECTED ) & TVIS_SELECTED;  
    228.   
    229.         // Must synthesize a TVN_SELCHANGING notification  
    230.         if ( pWnd )  
    231.         {  
    232.             tv.hdr.hwndFrom = GetSafeHwnd();  
    233.             tv.hdr.idFrom = GetWindowLong( GetSafeHwnd(), GWL_ID );  
    234.             tv.hdr.code = TVN_SELCHANGING;  
    235.   
    236.             tv.itemNew.hItem = hClickedItem;  
    237.             tv.itemNew.state = GetItemState( hClickedItem, 0xffffffff );  
    238.             tv.itemNew.lParam = GetItemData( hClickedItem );  
    239.   
    240.             tv.itemOld.hItem = NULL;  
    241.             tv.itemOld.mask = 0;  
    242.   
    243.             tv.action = TVC_BYMOUSE;  
    244.   
    245.             tv.ptDrag.x = point.x;  
    246.             tv.ptDrag.y = point.y;  
    247.   
    248.             pWnd->SendMessage( WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv );  
    249.         }  
    250.   
    251.         // If the previously selected item was selected, re-select it  
    252.         if ( bIsSelectedItemSelected )  
    253.             SetItemState( hSelectedItem, TVIS_SELECTED, TVIS_SELECTED );  
    254.   
    255.         // We want the newly selected item to toggle its selected state,  
    256.         // so unselect now if it was already selected before  
    257.         if ( bIsClickedItemSelected )  
    258.             SetItemState( hClickedItem, 0, TVIS_SELECTED );  
    259.         else  
    260.         {  
    261.             SelectItem(hClickedItem);  
    262.             SetItemState( hClickedItem, TVIS_SELECTED, TVIS_SELECTED );  
    263.         }  
    264.   
    265.         // If the previously selected item was selected, re-select it  
    266.         if ( bIsSelectedItemSelected && hSelectedItem != hClickedItem )  
    267.             SetItemState( hSelectedItem, TVIS_SELECTED, TVIS_SELECTED );  
    268.   
    269.         // Store as first selected item (if not already stored)  
    270.         if ( m_hFirstSelectedItem==NULL )  
    271.             m_hFirstSelectedItem = hClickedItem;  
    272.     }  
    273.     else  
    274.     {  
    275.         // Clear selection of all "multiple selected" items first  
    276.         ClearSelection();  
    277.   
    278.         // Then select the clicked item  
    279.         SelectItem( hClickedItem );  
    280.         SetItemState( hClickedItem, TVIS_SELECTED, TVIS_SELECTED );  
    281.   
    282.         // Store as first selected item  
    283.         m_hFirstSelectedItem = hClickedItem;  
    284.     }  
    285.   
    286.     // Selection process is now complete. Since we have 'eaten' the TVN_SELCHANGED   
    287.     // notification provided by Windows' treectrl, we must now produce one ourselves,  
    288.     // so that our parent gets to know about the change of selection.  
    289.     m_bSelectionComplete = TRUE;  
    290.   
    291.     if ( pWnd )  
    292.     {  
    293.         tv.hdr.hwndFrom = GetSafeHwnd();  
    294.         tv.hdr.idFrom = GetWindowLong( GetSafeHwnd(), GWL_ID );  
    295.         tv.hdr.code = TVN_SELCHANGED;  
    296.   
    297.         tv.itemNew.hItem = m_hClickedItem;  
    298.         tv.itemNew.state = GetItemState( m_hClickedItem, 0xffffffff );  
    299.         tv.itemNew.lParam = GetItemData( m_hClickedItem );  
    300.         tv.itemNew.mask = TVIF_HANDLE|TVIF_STATE|TVIF_PARAM;  
    301.   
    302.         tv.action = TVC_UNKNOWN;  
    303.   
    304.         pWnd->SendMessage( WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv );  
    305.     }  
    306. }  
    307.   
    308. void CTreeCtrlEx::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags )   
    309. {  
    310.     CWnd* pWnd = GetParent();  
    311.   
    312.     if ( nChar==VK_NEXT || nChar==VK_PRIOR )  
    313.     {  
    314.         if ( !( GetKeyState( VK_SHIFT )&0x8000 ) )  
    315.         {  
    316.             // User pressed Pg key without holding 'Shift':  
    317.             // Clear multiple selection (if multiple) and let base class do   
    318.             // normal selection work!  
    319.             if ( GetSelectedCount()>1 )  
    320.                 ClearSelection( TRUE );  
    321.   
    322.             CTreeCtrl::OnKeyDown( nChar, nRepCnt, nFlags );  
    323.             m_hFirstSelectedItem = GetSelectedItem();  
    324.             return;  
    325.         }  
    326.   
    327.         // Flag signaling that selection process is NOT complete.  
    328.         // (Will prohibit TVN_SELCHANGED from being sent to parent)  
    329.         m_bSelectionComplete = FALSE;  
    330.   
    331.         // Let base class select the item  
    332.         CTreeCtrl::OnKeyDown( nChar, nRepCnt, nFlags );  
    333.         HTREEITEM hSelectedItem = GetSelectedItem();  
    334.   
    335.         // Then select items in between  
    336.         SelectItems( m_hFirstSelectedItem, hSelectedItem );  
    337.   
    338.         // Selection process is now complete. Since we have 'eaten' the TVN_SELCHANGED   
    339.         // notification provided by Windows' treectrl, we must now produce one ourselves,  
    340.         // so that our parent gets to know about the change of selection.  
    341.         m_bSelectionComplete = TRUE;  
    342.   
    343.         if (pWnd)  
    344.         {  
    345.             NM_TREEVIEW tv;  
    346.             memset(&tv.itemOld, 0, sizeof(tv.itemOld));  
    347.   
    348.             tv.hdr.hwndFrom = GetSafeHwnd();  
    349.             tv.hdr.idFrom = GetWindowLong(GetSafeHwnd(), GWL_ID);  
    350.             tv.hdr.code = TVN_SELCHANGED;  
    351.   
    352.             tv.itemNew.hItem = hSelectedItem;  
    353.             tv.itemNew.state = GetItemState(hSelectedItem, 0xffffffff);  
    354.             tv.itemNew.lParam = GetItemData(hSelectedItem);  
    355.             tv.itemNew.mask = TVIF_HANDLE|TVIF_STATE|TVIF_PARAM;  
    356.   
    357.             tv.action = TVC_UNKNOWN;  
    358.   
    359.             pWnd->SendMessage(WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv);  
    360.         }  
    361.     }  
    362.     else if ( nChar==VK_UP || nChar==VK_DOWN )  
    363.     {  
    364.         // Find which item is currently selected  
    365.         HTREEITEM hSelectedItem = GetSelectedItem();  
    366.   
    367.         HTREEITEM hNextItem;  
    368.         if ( nChar==VK_UP )  
    369.             hNextItem = GetPrevVisibleItem( hSelectedItem );  
    370.         else  
    371.             hNextItem = GetNextVisibleItem( hSelectedItem );  
    372.   
    373.         if ( !( GetKeyState( VK_SHIFT )&0x8000 ) )  
    374.         {  
    375.             // User pressed arrow key without holding 'Shift':  
    376.             // Clear multiple selection (if multiple) and let base class do   
    377.             // normal selection work!  
    378.             if ( GetSelectedCount()>1 )  
    379.                 ClearSelection( TRUE );  
    380.   
    381.             if ( hNextItem )  
    382.                 CTreeCtrl::OnKeyDown( nChar, nRepCnt, nFlags );  
    383.             m_hFirstSelectedItem = GetSelectedItem();  
    384.             return;  
    385.         }  
    386.   
    387.         if ( hNextItem )  
    388.         {  
    389.             // Flag signaling that selection process is NOT complete.  
    390.             // (Will prohibit TVN_SELCHANGED from being sent to parent)  
    391.             m_bSelectionComplete = FALSE;  
    392.   
    393.             // If the next item is already selected, we assume user is  
    394.             // "moving back" in the selection, and thus we should clear   
    395.             // selection on the previous one  
    396.             BOOL bSelect = !( GetItemState( hNextItem, TVIS_SELECTED ) & TVIS_SELECTED );  
    397.   
    398.             // Select the next item (this will also deselect the previous one!)  
    399.             SelectItem( hNextItem );  
    400.   
    401.             // Now, re-select the previously selected item  
    402.             if ( bSelect || ( !( GetItemState( hSelectedItem, TVIS_SELECTED ) & TVIS_SELECTED ) ) )  
    403.                 SelectItems( m_hFirstSelectedItem, hNextItem );  
    404.   
    405.             // Selection process is now complete. Since we have 'eaten' the TVN_SELCHANGED   
    406.             // notification provided by Windows' treectrl, we must now produce one ourselves,  
    407.             // so that our parent gets to know about the change of selection.  
    408.             m_bSelectionComplete = TRUE;  
    409.   
    410.             if (pWnd)  
    411.             {  
    412.                 NM_TREEVIEW tv;  
    413.                 memset(&tv.itemOld, 0, sizeof(tv.itemOld));  
    414.   
    415.                 tv.hdr.hwndFrom = GetSafeHwnd();  
    416.                 tv.hdr.idFrom = GetWindowLong(GetSafeHwnd(), GWL_ID);  
    417.                 tv.hdr.code = TVN_SELCHANGED;  
    418.   
    419.                 tv.itemNew.hItem = hNextItem;  
    420.                 tv.itemNew.state = GetItemState(hNextItem, 0xffffffff);  
    421.                 tv.itemNew.lParam = GetItemData(hNextItem);  
    422.                 tv.itemNew.mask = TVIF_HANDLE|TVIF_STATE|TVIF_PARAM;  
    423.   
    424.                 tv.action = TVC_UNKNOWN;  
    425.   
    426.                 pWnd->SendMessage(WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv);  
    427.             }  
    428.         }  
    429.   
    430.         // Since the base class' OnKeyDown() isn't called in this case,  
    431.         // we must provide our own TVN_KEYDOWN notification to the parent  
    432.   
    433.         CWnd* pWnd = GetParent();  
    434.         if ( pWnd )  
    435.         {  
    436.             NMTVKEYDOWN tvk;  
    437.   
    438.             tvk.hdr.hwndFrom = GetSafeHwnd();  
    439.             tvk.hdr.idFrom = GetWindowLong( GetSafeHwnd(), GWL_ID );  
    440.             tvk.hdr.code = TVN_KEYDOWN;  
    441.   
    442.             tvk.wVKey = nChar;  
    443.             tvk.flags = 0;  
    444.   
    445.             pWnd->SendMessage( WM_NOTIFY, tvk.hdr.idFrom, (LPARAM)&tvk );  
    446.         }  
    447.     }  
    448.     else  
    449.         // Behave normally  
    450.         CTreeCtrl::OnKeyDown( nChar, nRepCnt, nFlags );  
    451. }  
    452.   
    453.   
    454. ///  
    455. // I want clicking on an item with the right mouse button to select the item,  
    456. // but not if there is currently a multiple selection  
    457.   
    458. void CTreeCtrlEx::OnRButtonDown( UINT nFlags, CPoint point )  
    459. {  
    460.     UINT nHitFlags = 0;  
    461.     HTREEITEM hClickedItem = HitTest( point, &nHitFlags );  
    462.   
    463.     if( nHitFlags&TVHT_ONITEM )  
    464.         if ( GetSelectedCount()<2 )  
    465.             SelectItem( hClickedItem );  
    466.   
    467.     CTreeCtrl::OnRButtonDown( nFlags, point );  
    468. }  
    469.   
    470.   
    471. ///  
    472. // Get number of selected items  
    473.   
    474. UINT CTreeCtrlEx::GetSelectedCount() const  
    475. {  
    476.     // Only visible items should be selected!  
    477.     UINT uCount=0;  
    478.     for ( HTREEITEM hItem = GetRootItem(); hItem!=NULL; hItem = GetNextVisibleItem( hItem ) )  
    479.         if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )  
    480.             uCount++;  
    481.   
    482.     return uCount;  
    483. }  
    484.   
    485.   
    486. ///  
    487. // Overloaded to catch our own special code  
    488.   
    489. HTREEITEM CTreeCtrlEx::GetNextItem(HTREEITEM hItem, UINT nCode)  
    490. {  
    491.     if (nCode==TVGN_EX_ALL)  
    492.     {  
    493.         // This special code lets us iterate through ALL tree items regardless   
    494.         // of their parent/child relationship (very handy)  
    495.         HTREEITEM hNextItem;  
    496.   
    497.         // If it has a child node, this will be the next item  
    498.         hNextItem = GetChildItem( hItem );  
    499.         if (hNextItem)  
    500.             return hNextItem;  
    501.   
    502.         // Otherwise, see if it has a next sibling item  
    503.         hNextItem = GetNextSiblingItem(hItem);  
    504.         if (hNextItem)  
    505.             return hNextItem;  
    506.   
    507.         // Finally, look for next sibling to the parent item  
    508.         HTREEITEM hParentItem=hItem;  
    509.         while (!hNextItem && hParentItem)  
    510.         {  
    511.             // No more children: Get next sibling to parent  
    512.             hParentItem = GetParentItem(hParentItem);  
    513.             hNextItem = GetNextSiblingItem(hParentItem);  
    514.         }  
    515.   
    516.         return hNextItem; // will return NULL if no more parents  
    517.     }  
    518.     else  
    519.         return CTreeCtrl::GetNextItem(hItem, nCode);    // standard processing  
    520. }  
    521.   
    522. ///  
    523. // Helpers to list out selected items. (Use similar to GetFirstVisibleItem(),   
    524. // GetNextVisibleItem() and GetPrevVisibleItem()!)  
    525.   
    526. HTREEITEM CTreeCtrlEx::GetFirstSelectedItem()  
    527. {  
    528.     for ( HTREEITEM hItem = GetRootItem(); hItem!=NULL; hItem = GetNextVisibleItem( hItem ) )  
    529.         if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )  
    530.             return hItem;  
    531.   
    532.     return NULL;  
    533. }  
    534.   
    535. HTREEITEM CTreeCtrlEx::GetNextSelectedItem( HTREEITEM hItem )  
    536. {  
    537.     for ( hItem = GetNextVisibleItem( hItem ); hItem!=NULL; hItem = GetNextVisibleItem( hItem ) )  
    538.         if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )  
    539.             return hItem;  
    540.   
    541.     return NULL;  
    542. }  
    543.   
    544. HTREEITEM CTreeCtrlEx::GetPrevSelectedItem( HTREEITEM hItem )  
    545. {  
    546.     for ( hItem = GetPrevVisibleItem( hItem ); hItem!=NULL; hItem = GetPrevVisibleItem( hItem ) )  
    547.         if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )  
    548.             return hItem;  
    549.   
    550.     return NULL;  
    551. }  
    552.   
    553.   
    554. ///  
    555. // Select/unselect item without unselecting other items  
    556.   
    557. BOOL CTreeCtrlEx::SelectItemEx(HTREEITEM hItem, BOOL bSelect/*=TRUE*/)  
    558. {  
    559.     HTREEITEM hSelItem = GetSelectedItem();  
    560.   
    561.     if ( hItem==hSelItem )  
    562.     {  
    563.         if ( !bSelect )  
    564.         {  
    565.             SelectItem( NULL );  
    566.             return TRUE;  
    567.         }  
    568.   
    569.         return FALSE;  
    570.     }  
    571.   
    572.     SelectItem( hItem );  
    573.     m_hFirstSelectedItem=hItem;  
    574.   
    575.     // Reselect previous "real" selected item which was unselected byt SelectItem()  
    576.     if ( hSelItem )  
    577.         SetItemState( hSelItem, TVIS_SELECTED, TVIS_SELECTED );  
    578.   
    579.     return TRUE;  
    580. }  
    581.   
    582. ///  
    583. // Select visible items between specified 'from' and 'to' item (including these!)  
    584. // If the 'to' item is above the 'from' item, it traverses the tree in reverse   
    585. // direction. Selection on other items is cleared!  
    586.   
    587. BOOL CTreeCtrlEx::SelectItems( HTREEITEM hFromItem, HTREEITEM hToItem )  
    588. {  
    589.     // Determine direction of selection   
    590.     // (see what item comes first in the tree)  
    591.     HTREEITEM hItem = GetRootItem();  
    592.   
    593.     while ( hItem && hItem!=hFromItem && hItem!=hToItem )  
    594.         hItem = GetNextVisibleItem( hItem );  
    595.   
    596.     if ( !hItem )  
    597.         return FALSE;   // Items not visible in tree  
    598.   
    599.     BOOL bReverse = hItem==hToItem;  
    600.   
    601.     // "Really" select the 'to' item (which will deselect   
    602.     // the previously selected item)  
    603.   
    604.     SelectItem( hToItem );  
    605.   
    606.     // Go through all visible items again and select/unselect  
    607.   
    608.     hItem = GetRootItem();  
    609.     BOOL bSelect = FALSE;  
    610.   
    611.     while ( hItem )  
    612.     {  
    613.         if ( hItem == ( bReverse ? hToItem : hFromItem ) )  
    614.             bSelect = TRUE;  
    615.   
    616.         if ( bSelect )  
    617.         {  
    618.             if ( !( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) )  
    619.                 SetItemState( hItem, TVIS_SELECTED, TVIS_SELECTED );  
    620.         }  
    621.         else  
    622.         {  
    623.             if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )  
    624.                 SetItemState( hItem, 0, TVIS_SELECTED );  
    625.         }  
    626.   
    627.         if ( hItem == ( bReverse ? hFromItem : hToItem ) )  
    628.             bSelect = FALSE;  
    629.   
    630.         hItem = GetNextVisibleItem( hItem );  
    631.     }  
    632.   
    633.     return TRUE;  
    634. }  
    635.   
    636.   
    637. ///  
    638. // Clear selected state on all visible items  
    639.   
    640. void CTreeCtrlEx::ClearSelection(BOOL bMultiOnly/*=FALSE*/)  
    641. {  
    642.     //  if ( !bMultiOnly )  
    643.     //      SelectItem( NULL );  
    644.   
    645.     for ( HTREEITEM hItem=GetRootItem(); hItem!=NULL; hItem=GetNextVisibleItem( hItem ) )  
    646.         if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )  
    647.             SetItemState( hItem, 0, TVIS_SELECTED );  
    648. }  
    649.   
    650.   
    651. ///  
    652. // If a node is collapsed, we should clear selections of its child items   
    653.   
    654. BOOL CTreeCtrlEx::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)   
    655. {  
    656.     NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;  
    657.   
    658.     if ( pNMTreeView->action == TVE_COLLAPSE )  
    659.     {  
    660.         HTREEITEM hItem = GetChildItem( pNMTreeView->itemNew.hItem );  
    661.   
    662.         while ( hItem )  
    663.         {  
    664.             if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )  
    665.                 SetItemState( hItem, 0, TVIS_SELECTED );  
    666.   
    667.             // Get the next node: First see if current node has a child  
    668.             HTREEITEM hNextItem = GetChildItem( hItem );  
    669.             if ( !hNextItem )  
    670.             {  
    671.                 // No child: Get next sibling item  
    672.                 if ( !( hNextItem = GetNextSiblingItem( hItem ) ) )  
    673.                 {  
    674.                     HTREEITEM hParentItem = hItem;  
    675.                     while ( !hNextItem )  
    676.                     {  
    677.                         // No more children: Get parent  
    678.                         if ( !( hParentItem = GetParentItem( hParentItem ) ) )  
    679.                             break;  
    680.   
    681.                         // Quit when parent is the collapsed node  
    682.                         // (Don't do anything to siblings of this)  
    683.                         if ( hParentItem == pNMTreeView->itemNew.hItem )  
    684.                             break;  
    685.   
    686.                         // Get next sibling to parent  
    687.                         hNextItem = GetNextSiblingItem( hParentItem );  
    688.                     }  
    689.   
    690.                     // Quit when parent is the collapsed node  
    691.                     if ( hParentItem == pNMTreeView->itemNew.hItem )  
    692.                         break;  
    693.                 }  
    694.             }  
    695.   
    696.             hItem = hNextItem;  
    697.         }  
    698.     }  
    699.   
    700.     *pResult = 0;  
    701.     return FALSE;   // Allow parent to handle this notification as well  
    702. }  
    703.   
    704.   
    705. ///  
    706. // Intercept TVN_SELCHANGED and pass it only to the parent window of the  
    707. // selection process is finished  
    708.   
    709. BOOL CTreeCtrlEx::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)  
    710. {  
    711.     // Return TRUE if selection is not complete. This will prevent the   
    712.     // notification from being sent to parent.  
    713.     return !m_bSelectionComplete;     
    714. }  
    715.   
    716.   
    717. ///  
    718. // Ensure the multiple selected items are drawn correctly when loosing/getting  
    719. // the focus  
    720.   
    721. BOOL CTreeCtrlEx::OnSetfocus(NMHDR* pNMHDR, LRESULT* pResult)   
    722. {  
    723.     Invalidate();  
    724.     *pResult = 0;  
    725.     return FALSE;  
    726. }  
    727.   
    728. BOOL CTreeCtrlEx::OnKillfocus(NMHDR* pNMHDR, LRESULT* pResult)   
    729. {  
    730.     Invalidate();  
    731.     *pResult = 0;  
    732.     return FALSE;  
    733. }  
    734.   
    735. void CTreeCtrlEx::OnLButtonDblClk(UINT nFlags, CPoint point)  
    736. {  
    737.     // We stop label editing.  
    738.     m_bEditLabelPending = FALSE;  
    739.     CTreeCtrl::OnLButtonDblClk(nFlags, point);  
    740. }  
    741.   
    742. void CTreeCtrlEx::OnTimer(/*UINT*/UINT_PTR nIDEvent)  
    743. {  
    744.     if (nIDEvent == TCEX_EDITLABEL)  
    745.     {  
    746.         // Stop the timer.  
    747.         KillTimer(m_idTimer);  
    748.   
    749.         // Invoke label editing.  
    750.         if (m_bEditLabelPending)  
    751.             EditLabel(GetSelectedItem());  
    752.   
    753.         m_bEditLabelPending = FALSE;  
    754.         return;  
    755.     }  
    756.   
    757.     CTreeCtrl::OnTimer(nIDEvent);  
    758. }  
    759.   
    760. ///  
    761. // Retreives a tree ctrl item given the item's data  
    762.   
    763. HTREEITEM CTreeCtrlEx::ItemFromData(DWORD dwData, HTREEITEM hStartAtItem/*=NULL*/const  
    764. {  
    765.     // Traverse all items in tree control  
    766.     HTREEITEM hItem;  
    767.     if ( hStartAtItem )  
    768.         hItem = hStartAtItem;  
    769.     else  
    770.         hItem = GetRootItem();  
    771.   
    772.     while ( hItem )  
    773.     {  
    774.         if ( dwData == (DWORD)GetItemData( hItem ) )  
    775.             return hItem;  
    776.   
    777.         // Get first child node  
    778.         HTREEITEM hNextItem = GetChildItem( hItem );  
    779.   
    780.         if ( !hNextItem )  
    781.         {  
    782.             // Get next sibling child  
    783.             hNextItem = GetNextSiblingItem( hItem );  
    784.   
    785.             if ( !hNextItem )  
    786.             {  
    787.                 HTREEITEM hParentItem=hItem;  
    788.                 while ( !hNextItem && hParentItem )  
    789.                 {  
    790.                     // No more children: Get next sibling to parent  
    791.                     hParentItem = GetParentItem( hParentItem );  
    792.                     hNextItem = GetNextSiblingItem( hParentItem );  
    793.                 }  
    794.             }  
    795.         }  
    796.   
    797.         hItem = hNextItem;  
    798.     }  
    799.   
    800.     return NULL;  
    801. }  
    802.   
    803.   
    804. /  
    805.   
    806. HTREEITEM GetTreeItemFromData(CTreeCtrl& treeCtrl, DWORD dwData, HTREEITEM hStartAtItem /*=NULL*/)  
    807. {  
    808.     // Traverse from given item (or all items if hFromItem is NULL)  
    809.     HTREEITEM hItem;  
    810.     if ( hStartAtItem )  
    811.         hItem=hStartAtItem;  
    812.     else  
    813.         hItem = treeCtrl.GetRootItem();  
    814.   
    815.     while ( hItem )  
    816.     {  
    817.         if ( dwData == (DWORD)treeCtrl.GetItemData( hItem ) )  
    818.             return hItem;  
    819.   
    820.         // Get first child node  
    821.         HTREEITEM hNextItem = treeCtrl.GetChildItem( hItem );  
    822.   
    823.         if ( !hNextItem )  
    824.         {  
    825.             // Get next sibling child  
    826.             hNextItem = treeCtrl.GetNextSiblingItem( hItem );  
    827.   
    828.             if ( !hNextItem )  
    829.             {  
    830.                 HTREEITEM hParentItem=hItem;  
    831.                 while ( !hNextItem && hParentItem )  
    832.                 {  
    833.                     // No more children: Get next sibling to parent  
    834.                     hParentItem = treeCtrl.GetParentItem( hParentItem );  
    835.                     hNextItem = treeCtrl.GetNextSiblingItem( hParentItem );  
    836.                 }  
    837.             }  
    838.         }  
    839.         hItem = hNextItem;  
    840.     }  
    841.     return NULL;  
    842. }  
    843.   
    844. /************************************************************************/  
    845. /*                                                                      */  
    846. /************************************************************************/  
    847.   
    848. BEGIN_MESSAGE_MAP(CDirTreeCtrl, CTreeCtrlEx)  
    849.     //{{AFX_MSG_MAP(CDirTreeCtrl)  
    850.     // NOTE - the ClassWizard will add and remove mapping macros here.  
    851.     //}}AFX_MSG_MAP  
    852.     //ON_NOTIFY_REFLECT(NM_CLICK, &CDirTreeCtrl::OnNMClick)  
    853.     ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, &CDirTreeCtrl::OnTvnItemexpanding)  
    854. END_MESSAGE_MAP()  
    855.   
    856. /  
    857. // CDirTreeCtrl message handlers  
    858. //程序调用的接口,显示一棵目录树,  
    859. //strRoot为根目录路径  
    860. BOOL CDirTreeCtrl::DisplayTree(LPCTSTR strRoot)  
    861. {  
    862.     SetItemHeight(20);  
    863.     SetTextColor(RGB(0X0,0X0,0XFF));  
    864.     DeleteAllItems();  
    865.     SetDirTreeStyle();  
    866.     if ( !AttachImgList() ) return FALSE;  
    867.   
    868.     DisplayDrives();  
    869.   
    870.     return TRUE;  
    871. }  
    872. //设置目录树属性  
    873. void CDirTreeCtrl::SetDirTreeStyle()  
    874. {  
    875.     DWORD dwStyle = GetWindowLong(m_hWnd, GWL_STYLE );  
    876.     dwStyle |= TVS_HASBUTTONS |  
    877.         TVS_HASLINES | TVS_LINESATROOT |  
    878.         /*TVS_CHECKBOXES |*/  
    879.         WS_BORDER | WS_TABSTOP ;  
    880.     m_treeStyle = dwStyle;  
    881.     SetWindowLong(m_hWnd, GWL_STYLE, dwStyle );  
    882. }  
    883. //获取系统图标  
    884. BOOL CDirTreeCtrl::AttachImgList()  
    885. {  
    886.     SHFILEINFOW shFinfo;  
    887.     HIMAGELIST hImgList = NULL;  
    888.   
    889.     if ( GetImageList( TVSIL_NORMAL ) ) m_imgList.Detach();  
    890.   
    891.     //char *szName="C:\\";  
    892.     //USES_CONVERSION; // 这个宏一定要加上,否则会出一堆错误    
    893.     //LPCWSTR pName=T2W(szName); // tchar ---> wchar   
    894.     hImgList = (HIMAGELIST)SHGetFileInfoW(  
    895.         /*pName*/L"C:\\",  
    896.         0,  
    897.         &shFinfo,  
    898.         sizeof( shFinfo ),  
    899.         SHGFI_SYSICONINDEX |  SHGFI_SMALLICON );  
    900.     if ( !hImgList )  
    901.     {  
    902.         m_strError = _T("无法得到系统图标文件!");  
    903.         return FALSE;  
    904.     }  
    905.     m_imgList.m_hImageList = hImgList;     
    906.   
    907.     SetImageList( &m_imgList, TVSIL_NORMAL );  
    908.     return TRUE;   
    909. }  
    910. //显示系统盘符  
    911. BOOL CDirTreeCtrl::DisplayDrives()  
    912. {  
    913.     DeleteAllItems();  
    914.   
    915.     TCHAR  szDrives[260];  
    916.     TCHAR* pDrive=NULL;  
    917.     if ( !GetLogicalDriveStrings( sizeof(szDrives), szDrives ) )  
    918.     {  
    919.         m_strError =_T("驱动信息获取失败!");  
    920.         return FALSE;  
    921.     }  
    922.   
    923.     pDrive = szDrives;    //szDrives 中的字符串格式:_T("C:\\0D:\\0D:\\0E:\\0")   
    924.   
    925.     m_hDirTreeRoot = InsertItem(_T("计算机"),15,25);//15 和是计算机的两个图标,前一个是没选中时的,后一个是选中时的  
    926.     //CStringArray strDrives;  
    927.     //CString strDrive;  
    928.     //while( *pDrive!=0 )  
    929.     //{  
    930.     //  strDrives.Add(pDrive);  
    931.     //  pDrive += _tcslen( pDrive ) + 1;  
    932.     //}  
    933.     //for (int n=0; n<strDrives.GetCount(); n++)  
    934.     //{  
    935.     //  strDrive=strDrives.GetAt(n);  
    936.     //  strDrive.SetAt(strDrive.GetLength()-1,_T('\0'));  //试验表明:uincode 的"\0"字符同样适用!!!  
    937.     //  HTREEITEM hParent = AddItem( m_hDirTreeRoot,strDrive  );  
    938.     //  if ( FindSubDir( strDrive ))  InsertItem(_T("dummy"),0,0,hParent);  
    939.     //    
    940.     //}  
    941.   
    942.     // 去掉盘符后的"\",下面的思路经验证也可行,而且更加简练  
    943.     int len;  
    944.     while( *pDrive!=0 )  
    945.     {  
    946.         len = (int)_tcslen(pDrive);  
    947.         pDrive[len-1] = _T('\0');  
    948.         HTREEITEM hParent = AddItem( m_hDirTreeRoot, pDrive );  
    949.         if ( FindSubDir( pDrive ))  AddSubDirAsItem(hParent);   
    950.         // 一个技巧先加入下一级子目录项,  
    951.         // 然后再点击该项后,首先去掉所有子项,然后再加入,  
    952.         // 这样的好处是在前面路径的方框中会有一个+号,  
    953.         // 因为如果把全部的目录一次加入,大约需要半个小时时间,所以采取点击时先去掉所有项,然后再增加子目录  
    954.         pDrive += len + 1;  
    955.     }  
    956.   
    957.     Expand( m_hDirTreeRoot, TVE_EXPAND );  
    958.     return TRUE;  
    959. }  
    960.   
    961.   
    962. //是否有子目录可展开  
    963. BOOL CDirTreeCtrl::FindSubDir(LPCTSTR strPath)  
    964. {  
    965.     CFileFind find;  
    966.     CString   strTemp = strPath;  
    967.     BOOL      bFind;  
    968.   
    969.     if ( strTemp.Right(1) == _T('\\') )        strTemp += _T("*.*");  
    970.     else        strTemp += _T("\\*.*");     
    971.   
    972.     bFind = find.FindFile( strTemp );     
    973.     while ( bFind )  
    974.     {  
    975.         bFind = find.FindNextFile();  
    976.         if ( find.IsDirectory() && !find.IsDots() )  
    977.         {  
    978.             return TRUE;  
    979.         }  
    980.         if ( !find.IsDirectory()/* && m_bShowFiles*/ )  
    981.             return TRUE;         
    982.     }  
    983.     return FALSE;  
    984. }  
    985.   
    986. //获取全目录  
    987. CString CDirTreeCtrl::GetFullPath(HTREEITEM hItem)  
    988. {  
    989.     CString strReturn;  
    990.     CString strTemp;  
    991.     HTREEITEM hParent = hItem;  
    992.   
    993.     strReturn = "";  
    994.   
    995.     while ( hParent )  
    996.     {  
    997.   
    998.         strTemp  = GetItemText( hParent );  
    999.         if(strTemp != _T("计算机"))  
    1000.         {  
    1001.             if ( strTemp.Right(1) !=  _T("\\") )     strTemp += _T("\\");  
    1002.             strReturn = strTemp + strReturn;  
    1003.         }  
    1004.         hParent = GetParentItem( hParent );  
    1005.     }  
    1006.   
    1007.     return strReturn;  
    1008. }  
    1009.   
    1010.   
    1011.   
    1012.   
    1013. // 需要在此节点上,加入它的整个子目录和下一级的子目录,作为迭代加入  
    1014. BOOL CDirTreeCtrl::AddSubDirAsItem(HTREEITEM hParent)  
    1015. {  
    1016.     CString strPath,strFileName;  
    1017.     HTREEITEM hChild;  
    1018.   
    1019.     //---------------------去除该父项下所有的子项------------  
    1020.     // 因为有dummy项,并且有时子目录再次打开,或子目录会刷新等,因此必须去除。  
    1021.     while ( ItemHasChildren(hParent))  
    1022.     {  
    1023.         hChild = GetChildItem(hParent);   
    1024.         DeleteItem( hChild );  
    1025.   
    1026.     }  
    1027.   
    1028.     //-----------------------装入该父项下所有子项--------------  
    1029.     strPath = GetFullPath(hParent);  // 从本节点开始到根的路径  
    1030.     CString strSearchCmd = strPath;  
    1031.     if( strSearchCmd.Right( 1 ) != _T( "\\" )) strSearchCmd += _T( "\\" );  
    1032.     strSearchCmd += _T( "*.*" );  
    1033.     CFileFind find;  
    1034.     BOOL bContinue = find.FindFile( strSearchCmd );  
    1035.     while ( bContinue )  
    1036.     {  
    1037.         bContinue = find.FindNextFile();  
    1038.         strFileName = find.GetFileName();  
    1039.   
    1040.         if ( !find.IsHidden() && ! find.IsDots() && find.IsDirectory() )  
    1041.         {  
    1042.             hChild = AddItem( hParent, strFileName );  
    1043.             if ( FindSubDir( GetFullPath(hChild) ))  AddSubDirAsItem1(hChild);   
    1044.             // 一个技巧:先加入下一级子目录项,  
    1045.             // 然后再点击该项后,再先去掉所有子项,然后再加入,  
    1046.             // 这样的好处是在前面路径的方框中会有一个+号,  
    1047.             // 因为如果把全部的目录一次加入,大约需要半个小时时间,所以采取点击时先去掉所有项,然后再增加子目录  
    1048.   
    1049.         }  
    1050.         if ( !find.IsHidden() && ! find.IsDots() && !find.IsDirectory() )  
    1051.         {  
    1052.             InsertItem( strFileName, 0, 0, hParent );  
    1053.         }  
    1054.   
    1055.     }  
    1056.   
    1057.     //  
    1058.   
    1059.   
    1060.     return TRUE;  
    1061.   
    1062. }  
    1063.   
    1064.   
    1065. //仅仅装入下一级子目录  
    1066. BOOL CDirTreeCtrl::AddSubDirAsItem1(HTREEITEM hParent)  
    1067. {  
    1068.     CString strPath,strFileName;  
    1069.     HTREEITEM hChild;  
    1070.   
    1071.     //---------------------去除该父项下所有的子项------------  
    1072.     // 因为有dummy项,并且有时子目录再次打开,或子目录会刷新等,因此必须去除。  
    1073.     while ( ItemHasChildren(hParent))  
    1074.     {  
    1075.         hChild = GetChildItem(hParent);   
    1076.         DeleteItem( hChild );  
    1077.     }  
    1078.   
    1079.     //-----------------------装入该父项下所有子项--------------  
    1080.     strPath = GetFullPath(hParent);  // 从本节点开始到根的路径  
    1081.     CString strSearchCmd = strPath;  
    1082.     if( strSearchCmd.Right( 1 ) != _T( "\\" )) strSearchCmd += _T( "\\" );  
    1083.     strSearchCmd += _T( "*.*" );  
    1084.     CFileFind find;  
    1085.     BOOL bContinue = find.FindFile( strSearchCmd );  
    1086.     while ( bContinue )  
    1087.     {  
    1088.         bContinue = find.FindNextFile();  
    1089.         strFileName = find.GetFileName();  
    1090.   
    1091.         if ( !find.IsHidden() && ! find.IsDots() && find.IsDirectory() )  
    1092.         {  
    1093.             hChild = AddItem( hParent, strFileName );  
    1094.         }  
    1095.         if ( !find.IsHidden() && ! find.IsDots() && !find.IsDirectory() )  
    1096.         {  
    1097.             InsertItem( strFileName, 0, 0, hParent );  
    1098.         }  
    1099.   
    1100.     }  
    1101.   
    1102.     //  
    1103.   
    1104.   
    1105.     return TRUE;  
    1106.   
    1107. }  
    1108.   
    1109. //添加项  
    1110. HTREEITEM CDirTreeCtrl::AddItem(HTREEITEM hParent, LPCTSTR strName)  
    1111. {  
    1112.     // 获取路径  
    1113.     CString strPath = GetFullPath(hParent);  
    1114.     CString strTemp = strPath + CString(strName);  
    1115.   
    1116.     if ( strTemp.Right(1) !=  _T("\\") )     strTemp += _T("\\");  
    1117.   
    1118.     SHFILEINFO shFinfo;  
    1119.     int iIcon, iIconSel;  
    1120.   
    1121.   
    1122.     if ( !SHGetFileInfo( strTemp,  
    1123.         0,  
    1124.         &shFinfo,  
    1125.         sizeof( shFinfo ),  
    1126.         SHGFI_ICON |  
    1127.         SHGFI_SMALLICON ) )  
    1128.     {  
    1129.         m_strError = _T("系统图表获取失败!");  
    1130.         return NULL;  
    1131.     }  
    1132.   
    1133.     iIcon = shFinfo.iIcon;  
    1134.   
    1135.     // we only need the index from the system image list  
    1136.     DestroyIcon( shFinfo.hIcon );  
    1137.   
    1138.     if ( !SHGetFileInfo( strTemp,  
    1139.         0,  
    1140.         &shFinfo,  
    1141.         sizeof( shFinfo ),  
    1142.         SHGFI_ICON | SHGFI_OPENICON |  
    1143.         SHGFI_SMALLICON ) )  
    1144.     {  
    1145.         m_strError =  _T("系统图表获取失败!");  
    1146.         return NULL;  
    1147.     }  
    1148.   
    1149.     iIconSel = shFinfo.iIcon;  
    1150.   
    1151.     // we only need the index of the system image list  
    1152.     DestroyIcon( shFinfo.hIcon );  
    1153.   
    1154.     return InsertItem( strName, iIcon, iIconSel, hParent );  
    1155. }  
    1156.   
    1157.   
    1158. //这里利用反射实现此函数,好处是可以把消息的处理完全封闭到类内,有利于使用  
    1159. //父窗口去掉对此消息的处理即可,没有处理,消息自然返回  
    1160. //void CDirTreeCtrl::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)  
    1161. //{  
    1162. //  // TODO: Add your control notification handler code here  
    1163. //  
    1164. //  
    1165. //  CPoint myPoint;  
    1166. //  UINT uFlag;  
    1167. //  
    1168. //  GetCursorPos(&myPoint);  
    1169. //  ScreenToClient(&myPoint);  
    1170. //  HTREEITEM hItem = HitTest(myPoint, &uFlag);  
    1171. //  if(NULL == hItem ) return;  
    1172. //  
    1173. //  if (_T("计算机")==GetItemText(hItem))  return;  
    1174. //  
    1175. //  // 用户点选了一个目录项  
    1176. //  // (TVHT_ONITEM & uFlag)的原因:如果不添加,即使在离图标或标识的较远的地方点一下左键(没在正上面),也会有有树的展开和收缩动作  
    1177. //  // (0x0010&uFlag) 如果不加此项,则点击+号时,AddSubDirAsItem不会被调用,下一级的有子目录的文件夹前面就没有+号  
    1178. //  // #define TVHT_ONITEMBUTTON   0x0010  我是通过跟踪试验找到这个值的   
    1179. //  if ((TVHT_ONITEM & uFlag)||(0x0010&uFlag))  
    1180. //  {  
    1181. //      AddSubDirAsItem(hItem);  
    1182. //  }  
    1183. //  else return;  
    1184. //  Expand( hItem, TVE_EXPAND );  
    1185. //  
    1186. //  
    1187. //  
    1188. //  BOOL bCheck;  
    1189. //  if(hItem && (TVHT_ONITEMSTATEICON & uFlag))  
    1190. //  {  
    1191. //         bCheck = GetCheck(hItem);  
    1192. //         SetChildCheck(hItem, !bCheck);  
    1193. //  }  
    1194. //  
    1195. //  
    1196. //  
    1197. //  *pResult = 0;  
    1198. //}  
    1199.   
    1200. //这里也是利用反射,好处是可以把消息的处理完全封闭到类内,实现封闭  
    1201. void CDirTreeCtrl::OnTvnItemexpanding(NMHDR *pNMHDR, LRESULT *pResult)  
    1202. {  
    1203.     LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);  
    1204.     // TODO: Add your control notification handler code here  
    1205.     //HTREEITEM hItem = GetSelectedItem();  // 注意:用这个函数不行,在+号打开时,子目录总是没有+号,尽管子目录中有子项  
    1206.     TV_ITEM tvi= pNMTreeView->itemNew;  
    1207.     HTREEITEM hItem = tvi.hItem;  
    1208.   
    1209.     if(NULL == hItem ) return;  
    1210.   
    1211.     if (_T("计算机")==GetItemText(hItem))  return;  
    1212.   
    1213.     AddSubDirAsItem(hItem);  
    1214.   
    1215.   
    1216.   
    1217.     *pResult = 0;  
    1218. }  

    展开全文
  • MFC 树控件CTreeCtrl

    2018-11-04 20:14:42
    常用属性设置: 属性 含义 has buttons True 有展开按钮 has lines True 有展开线 lines at root True 有根节点 ......
  • 1.0 从工具箱中拖树型控件到对话框窗口,控件ID IDC_WEB_TREE ,如下图所示 ... CTreeCtrl m_TreeCtrl; //用于与控件相连 CImageList m_ImageListTree; //用于存放图片 3.0 控件与类对象相...
  • MFC树形控件(CTreeCtrl)用法(下)

    万次阅读 2012-10-07 20:45:25
    Control的简介、通知消息以及相关数据结构,本节继续讲下半部分,包括树形控件的创建、CTreeCtrl类的主要成员函数和应用实例。  树形控件的创建  MFC为树形控件提供了CTreeCtrl类,它封装了树形控件的所有...
  • 树形控件可以用于树形的结构,其中有一个根接点(Root)然后下面有许多子结点,而每个子结点上有允许有一个或多...MFC中使用CTreeCtrl类来封装树形控件的各种操作。通过调用 BOOL Create( DWORD dwStyle, const RECT& rec
  • Ctreectrl

    2014-11-05 10:48:03
    MFC中使用CTreeCtrl类来封装树形控件的各种操作。通过调用 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些树形控件的
  • CTreeCtrl

    2009-05-12 13:54:00
    MFC中使用CTreeCtrl类来封装树形控件的各种操作。通过调用BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些树形控件的专用
  • CTreectrl

    2011-06-03 00:05:00
    树控制的数据结构树控制的应用技巧示例CTreeCtrl的用法1.取得或设定项目的信息2.取得与设定项目的状态3.取得与设定项目的图形4. 取得与设定项目的文本5. 查询 CTreeCtrl 中项目的个数6.查询hItem 的父项目的句柄7....
  • CTreeCtrl用法

    2013-07-31 17:18:01
    树控制(CTreeCtrl)主要用来显示具有一定层次结构的数据项,如资源管理器中的磁盘目录等,以供用户在其中进行各种选择。树控制中的每个数据项包括数据项名称的文本字符串和用于表示该数据项的图像,每个数据项下面...
  • MFC 树形控件CTreeCtrl显示文件路径及文件

    万次阅读 热门讨论 2020-06-28 20:10:23
    在上篇文章中简单讲述了"MFC单文档分割窗口显示图片",但是我想实现的是左边显示图片的路径,右边显示图片的情况,所以... CTreeCtrl(树形控件):用树结构显示一组信息,并能反映这些信息的层次关系.首先声明:该文章主要...
  • 在VS2010下可编译运行,MFC CtreeCtrl 保存为.xml格式,提供 bool LoadXmlFile(CTreeCtrl& m_tree, string& szFileName) 函数保存MFC CtreeCtrl,并提供 bool CreateXmlFile(CTreeCtrl& m_tree, string& ...
  • VC++ CTreeCtrl自绘

    2020-01-13 17:13:10
    头文件声明...#define _OWNER_DRAWN_TREE // 自绘CTreeCtrl,可支持背景图片显示功能 class CSWTreeCtrl : public CTreeCtrl { friend class CSWListTreeCtrl; DECLARE_DYNAMIC(CSWTreeCtrl) // 成...
  • 一步一步教你实现CTreeCtrl 自绘

    万次阅读 多人点赞 2016-08-01 10:05:21
    一步一步教你实现CTreeCtrl 自绘  -------BY wojiushi3344  QQ:513670524 转载请说明出处    源代码下载  最近因工作需求,需要自绘CTreeCtrl。由于原来从来没有自绘过,开始在网上搜索资料,查询(因此本文...
  • CTreeCtrl::SelectItem(hItem); CTreeCtrl::SetItemState(hFocus, TVIS_SELECTED, TVIS_SELECTED); CTreeCtrl::SelectItem(hItem); 其中hFocus是当前选中的item,hItem是要选中的item 这种情况实现的多选,在按住...
1 2 3 4 5 ... 20
收藏数 4,112
精华内容 1,644
关键字:

ctreectrl