在上篇文章中简单讲述了"MFC单文档分割窗口显示图片",但是我想实现的是左边显示图片的路径,右边显示图片的情况,所以这里需要讲述如何使用控件List Control和Tree Control.
CListCtrl(列表控件):可以用大图标、小图标、列表、报表四种不同方式显示一组信息.
CTreeCtrl(树形控件):用树结构显示一组信息,并能反映这些信息的层次关系.
首先声明:该文章主要是数字图形处理知识并结合liujiannan_1987的上传资源讲述,在此感谢该作者:
http://download.csdn.net/download/liujiannan_1987/1528908
第一部分 新建项目名为"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:\
此时如修改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(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;
}
运行结果如下:
HICON hIcon = theApp.LoadIcon(IDI_ICON1); //图标句柄
m_ImageList.Add(hIcon); //图标添加到图像序列
访问图标时m_hRoot = m_tree.InsertItem("我的电脑",0,0);为第一张ICON图标.推荐Bruce_Zeng文章"MFC树形控件(CTreeCtrl)用法".但是我没有成功,可能是获取大小时有图标会越界.
第六部分 调用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(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你上传的资源.最近有些忙,过后还将完成图标等工作及下篇"左边显示路径,右边显示图片".该文章资源下载地址:http://download.csdn.net/detail/eastmount/6917799
(By:Eastmount 2014-2-13夜1点 原创:http://blog.csdn.net/eastmount)