閱讀667 返回首頁    go 阿裏雲 go 技術社區[雲棲]


MFC 樹形控件CTreeCtrl顯示文件路徑及文件

在上篇文章中簡單講述了"MFC單文檔分割窗口顯示圖片",但是我想實現的是左邊顯示圖片的路徑,右邊顯示圖片的情況,所以這裏需要講述如何使用控件List ControlTree Control.
    CListCtrl(列表控件):可以用大圖標、小圖標、列表、報表四種不同方式顯示一組信息.
    CTreeCtrl(樹形控件):用樹結構顯示一組信息,並能反映這些信息的層次關係.
首先聲明:該文章主要是數字圖形處理知識並結合liujiannan_1987的上傳資源講述,在此感謝該作者:
https://download.csdn.net/download/liujiannan_1987/1528908

一.CTreeCtrl顯示文件路徑

第一部分 新建項目名為"TreeShow"的MFC基於對話框的應用程序.
資源視圖中修改對話框IDD_TREESHOW_DIALOG,刪除"TODO"和按鈕,從工具箱中添加Tree Control(左)和List Control控件,設置CTreeCtrl的ID為IDC_TREE,屬性Scroll(啟動水平垂直滾動)、Horizontal Scroll(具有水平滾動)、Transparent(透明背景)為True.設置CListCtrl的ID為IDC_LIST.如下圖:

第二部分 調用"項目"->"類向導"添加成員變量.
在類向導中選擇類名"CTreeViewDlg","成員變量"中添加變量:
(控件ID-類型-成員)IDC_LIST-CListCtrl-m_list、IDC_TREE-CTreeCtrl-m_tree.
添加自定義受保護變量:CImageList-m_ImageList、HTREEITEM-m_hRoot.添加後XXXDlg.h中顯示如下:

public:
	CListCtrl m_list;        //列表控件 IDC_LIST
	CTreeCtrl m_tree;        //樹形控件 IDC_TREE
protected:
	CImageList m_ImageList;  //圖像列表(相同大小圖像集合) 
	HTREEITEM m_hRoot;       //句柄 CTreeCtrl的根結點"我的電腦"

第三部分 調用"項目"->"類向導"添加方法.
1.在類導向中選擇類名"CTreeShowDlg","方法"中點擊"添加方法"公有函數void GetLogicalDrives(HTREEITEM hParent).具體代碼如下:

//函數功能:獲取驅動器 參數:路徑名                       
void CTreeShowDlg::GetLogicalDrives(HTREEITEM hParent)
{
	//獲取係統分區驅動器字符串信息
	size_t szAllDriveStrings = GetLogicalDriveStrings(0,NULL);           //驅動器總長度
	char *pDriveStrings = new char[szAllDriveStrings + sizeof(_T(""))];  //建立數組
	GetLogicalDriveStrings(szAllDriveStrings,pDriveStrings);
	size_t szDriveString = strlen(pDriveStrings);                        //驅動大小
	while(szDriveString > 0)
	{
		m_tree.InsertItem(pDriveStrings,hParent);       //在父節點hParent下添加盤符
		pDriveStrings += szDriveString + 1;             //pDriveStrings即C:\ D:\ E:\盤
		szDriveString = strlen(pDriveStrings);
	}
}

其中DWORD GetLogicalDriveStrings(DWORD nBuffer,LPTSTR lpBuffer)是Win32 API中獲取係統分區信息函數,獲取字符,其中包含當前所有邏輯驅動器的根驅動器路徑,nBuffer是緩衝區大小,lpBuffer是邏輯驅動器名稱字串.該函數將所有盤符信息以lpBuffer返回,如A:\<null>C:\<null>D:\<null><null>兩個NULL終止.
此時如修改CTreeShowDlg::OnInitDialog()函數,添加相應代碼能顯示如下(該部分代碼後麵3將詳細講述):

2.同理通過"類向導"添加公有函數void GetDriveDir(HTREEITEM hParent)具體代碼如下:

//函數功能:獲取驅動盤符下所有子項文件夾
void CTreeShowDlg::GetDriveDir(HTREEITEM hParent)
{
	HTREEITEM hChild = m_tree.GetChildItem(hParent);   //獲取指定位置中的子項
	while(hChild)                                      
	{
		CString strText = m_tree.GetItemText(hChild);  //檢索列表中項目文字
		if(strText.Right(1) != "\\")                   //從右邊1開始獲取從右向左nCount個字符
			strText += _T("\\");
		strText += "*.*";
		//將當前目錄下文件枚舉並InsertItem樹狀顯示
		CFileFind file;                                       //定義本地文件查找
	    BOOL bContinue = file.FindFile(strText);              //查找包含字符串的文件
		while(bContinue)
		{
            bContinue = file.FindNextFile();                  //查找下一個文件
			if(file.IsDirectory() && !file.IsDots())          //找到文件為內容且不為點"."
		        m_tree.InsertItem(file.GetFileName(),hChild); //添加盤符路徑下樹狀文件夾
		}
		GetDriveDir(hChild);                                  //遞歸調用
		hChild = m_tree.GetNextItem(hChild,TVGN_NEXT);        //獲取樹形控件TVGN_NEXT下兄弟項
	}
}

其中CTreeCtrl::GetNextItem(HTREEITEM hItem,UINT nCode)是MFC中樹形控件和列表控件用來獲取下一項,常用來遍曆.參數hItem是一個tree項的句柄,nCode一個用來指示與hItem的關係的類型的標誌.上述代碼用到TVGN_NEXT來獲取下一個兄弟項.詳見GetNextItem.
通過AfxMessageBox(strText)打樁輸出,可以發現它獲取的路徑為"C:\*.*",然後為"$360Section\*.*"依次遞歸遍曆;再通過GetNextItem(hChild,TVGN_NEXT)循環輸出下一個兄弟項"D:\*.*",遞歸D盤子項;再到兄弟項E盤等.這就是該部分代碼實現的功能.添加相應代碼顯示如下(該部分代碼後麵3將詳細講述):

3.修改TreeShowDlg.cpp中BOOL CTreeShowDlg::OnInitDialog()初始化函數才能實現顯示,添加代碼如下:

BOOL CTreeShowDlg::OnInitDialog()
{
	...
	// 設置此對話框的圖標。當應用程序主窗口不是對話框時,框架將自動
	//  執行此操作
	SetIcon(m_hIcon, TRUE);			// 設置大圖標
	SetIcon(m_hIcon, FALSE);		// 設置小圖標

	// TODO: 在此添加額外的初始化代碼
	m_ImageList.Create(32,32,ILC_COLOR32,10,30);     //創建圖像序列CImageList對象 
	m_list.SetImageList(&m_ImageList,LVSIL_NORMAL);  //為樹形控件設置圖像序列   
	m_tree.ModifyStyle(NULL,TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT|TVS_EDITLABELS);
    m_hRoot = m_tree.InsertItem("我的電腦");         //插入根節點
	GetLogicalDrives(m_hRoot);                      //自定義函數 獲取驅動
	GetDriveDir(m_hRoot);                           //自定義函數 獲取驅動子項
	m_tree.Expand(m_hRoot,TVE_EXPAND);              //展開或折疊子項列表 TVE_EXPAND展開列表 
	return TRUE;  // 除非將焦點設置到控件,否則返回 TRUE
}

(1).BOOLCImageList::Create( int cx, int cy, UINT nFlags, int nInitial, int nGrow )函數初始化圖像列表並綁定對象.cx定義圖像的寬度32像素,cy定義圖象的高度32像素,nFlags確定建立圖像列表的類型ILC_COLOR32 32位真彩,nInitial用來確定圖像列表包含的圖像數量,nGrow用來確定圖像列表可控製的圖像數量(增加容量時至少增加nGrow個單位).
(2).CImageList* SetImageList( CImageList *pImageList, intnImageListType )此成員函數來設置一個tree view控件的常規或狀態圖像控製列表.參數pImageList為指向圖像列表的標識,如果pImageList為NULL則所有的圖像都將從樹控製中被清除;nImageListType為圖像列表設置的類型,TVSIL_NORMAL 設置正常圖像列,其中包括選中和非選中兩種圖標.
(3).ModifyStyle(DWORD dwRemove,DWORD dwAdd,UINT nFlags=0)修改窗口風格.dwRemove指定修改時要刪除的窗風格,dwAdd指定修改時將要增加的窗口風格,也可以調用Win32 API函數SetWindowLong設置指定窗口屬性.

DWORD dwStyle = GetWindowLong(m_tree.m_hWnd,GWL_STYLE);
dwStyle |= TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT;
SetWindowLong(m_tree.m_hWnd,GWL_STYLE,dwStyle);

再調用InsertItem插入根節點"我的電腦",通過GetLogicalDrives(m_hRoot)顯示驅動器盤符樹狀信息,GetDriveDir(m_hRoot)顯示驅動子項文件夾信息.Expand是展開"我的電腦"列表,否則默認為折疊狀.

 二.顯示子項下文件夾並添加文件夾圖標

通過上麵的講述我們可以發現隻是實現了展開盤符下一層的路徑文件夾,但是繼續下去的文件夾如何展開,下麵將講述,但不將繼續敘述其中的函數功能.
第四部分 實現子項的孩子文件夾顯示
1.打開"項目"->"類導向"->選擇"CTreeShowDlg"類->"方法"中添加方法:CString GetFullPath(HTREEITEM hCurrent).具體代碼如下:

//函數功能:獲取樹項目全根路徑
CString CTreeShowDlg::GetFullPath(HTREEITEM hCurrent)
{
	CString strTemp;
	CString strReturn = "";
	while(hCurrent != m_hRoot)
	{
		strTemp = m_tree.GetItemText(hCurrent);    //檢索列表中項目文字
		if(strTemp.Right(1) != "\\")
			strTemp += "\\";
		strReturn = strTemp  + strReturn;        
		hCurrent = m_tree.GetParentItem(hCurrent); //返回父項目句柄
	}
	return strReturn;
}

2.同理,添加方法:void AddSubDir(HTREEITEM hParent).該函數添加子目錄,調用GetFullPath()獲取全路徑.具體代碼如下:

//函數功能:添加子目錄
void CTreeShowDlg::AddSubDir(HTREEITEM hParent)
{
	CString strPath = GetFullPath(hParent);     //獲取全路徑
	if(strPath.Right(1) != "\\")
		strPath += "\\";
	strPath += "*.*";
	CFileFind file;
	BOOL bContinue = file.FindFile(strPath);    //查找包含字符串的文件
	while(bContinue)
	{
		bContinue = file.FindNextFile();        //查找下一個文件
		if(file.IsDirectory() && !file.IsDots())
		    m_tree.InsertItem(file.GetFileName(),hParent);
	}
}

3."項目"->"類導向"->選擇"CTreeShowDlg"類->"命令"中選擇"IDC_TREE"對象ID->雙擊消息"TVN_ITEMEXPANDED",並添加成員函數void CTreeShowDlg::OnItemexpandedTree(NMHDR *pNMHDR, LRESULT *pResult).具體代碼如下:

//函數功能:展開事件函數
void CTreeShowDlg::OnItemexpandedTree(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);

	// TODO: 在此添加控件通知處理程序代碼
	TVITEM item = pNMTreeView->itemNew;                  //發送\接受關於樹形視圖項目信息
	if(item.hItem == m_hRoot)
		return;
    HTREEITEM hChild = m_tree.GetChildItem(item.hItem);  //獲取指定位置中的子項
	while(hChild)
	{
		AddSubDir(hChild);                               //添加子目錄
		hChild = m_tree.GetNextItem(hChild,TVGN_NEXT);   //獲取樹形控件TVGN_NEXT下兄弟項
	}
	*pResult = 0;
}

運行結果如下:

第五部分 添加文件夾圖標
具體方法如下:找到文件夾32*32ICON圖標,保存到工程的res目錄下.然後在Resource View資源視圖中,右鍵點擊Icon節點,在右鍵菜單中選擇“Add Resource..",彈出“Add Resource”對話框從左邊“Resource type”列表中選擇“Icon”,點擊右邊的“Import...”按鈕即可導入.設置圖標為IDI_ICON1.同時修改OnInitDialog()函數:
HICON hIcon = theApp.LoadIcon(IDI_ICON1);        //圖標句柄
m_ImageList.Add(hIcon);                          //圖標添加到圖像序列
訪問圖標時m_hRoot = m_tree.InsertItem("我的電腦",0,0);為第一張ICON圖標.推薦Bruce_Zeng文章"MFC樹形控件(CTreeCtrl)用法".但是我沒有成功,可能是獲取大小時有圖標會越界.

三.CListCtrl顯示文件夾中文件

第六部分 調用CListCtrl顯示文件夾中文件
"項目"->"類導向"->選擇"CTreeShowDlg"類->"命令"中選擇"IDC_TREE"對象ID->雙擊消息"TVN_SELCHANGED"生成成員函數:void CTreeShowDlg::OnSelchangedTree(NMHDR *pNMHDR, LRESULT *pResult),通過如下代碼顯示在CListCtrl中.

//函數功能:選中事件顯示圖標
void CTreeShowDlg::OnSelchangedTree(NMHDR *pNMHDR, LRESULT *pResult)
{
	//LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
	// TODO: 在此添加控件通知處理程序代碼
	m_list.DeleteAllItems();
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	TVITEM item = pNMTreeView->itemNew;
	if(item.hItem == m_hRoot)
		return;
	CString str = GetFullPath(item.hItem);
    if(str.Right(1) != "\\")
	   str += "\\";
	str += "*.*";
	CFileFind file;
	BOOL bContinue = file.FindFile(str);
	while(bContinue)
	{
		bContinue = file.FindNextFile();
		if(!file.IsDirectory() && !file.IsDots())
		{
		    SHFILEINFO info;
			CString temp = str;
			int index = temp.Find("*.*");
			temp.Delete(index,3);
		    SHGetFileInfo(temp + file.GetFileName(),0,&info,sizeof(&info),SHGFI_DISPLAYNAME | SHGFI_ICON);
		    int i = m_ImageList.Add(info.hIcon);
		    m_list.InsertItem(i,info.szDisplayName,i);
		}
	}
	*pResult = 0;
}

該部分代碼希望讀者自己詳細閱讀,非常不錯的一段代碼,完全轉自liujiannan_1987的上傳資源.運行結果如下:

四.總結

個人感覺該文章還不錯,主要是結合自己數字圖像處理知識,希望文章能夠對大家有所幫助,同時如果文章中有錯誤或不足之處,還請大家海涵.同時感謝liujiannan_1987你上傳的資源.最近有些忙,過後還將完成圖標等工作及下篇"左邊顯示路徑,右邊顯示圖片".該文章資源下載地址:https://download.csdn.net/detail/eastmount/6917799

(By:Eastmount 2014-2-13夜1點 原創:https://blog.csdn.net/eastmount)

 

最後更新:2017-04-03 12:55:04

  上一篇:go linux驅動開發--中斷:按鍵中斷
  下一篇:go 連載:麵向對象葵花寶典:思想、技巧與實踐(10) - “抽象” 詳解